Implement Ocean LOD management and enhance grid generation with wireframe support
This commit is contained in:
87
src/main.ts
87
src/main.ts
@@ -1,6 +1,6 @@
|
||||
import { vec3, mat4 } from 'gl-matrix';
|
||||
import { Camera } from './Camera';
|
||||
import { Grid } from './Grid';
|
||||
import { OceanLOD } from './OceanLOD';
|
||||
import { createProgram } from './Shader';
|
||||
import * as Config from './constants';
|
||||
|
||||
@@ -112,8 +112,8 @@ function initFBO() {
|
||||
// set the filtering so we don't need mips
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);
|
||||
|
||||
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, textureFBO, 0);
|
||||
|
||||
@@ -131,6 +131,7 @@ 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;
|
||||
@@ -140,14 +141,17 @@ var keyboardZoom = 0;
|
||||
var keysPressed: Set<string> = new Set();
|
||||
/** Objects and states*/
|
||||
var camera: Camera;
|
||||
var oceanGrid: Grid;
|
||||
var oceanLOD: OceanLOD;
|
||||
var curRotX = Config.CAMERA_DEFAULT_ROT_X;
|
||||
var curRotY = Config.CAMERA_DEFAULT_ROT_Y;
|
||||
var wireframeMode = false;
|
||||
function drawScene() {
|
||||
fps++;
|
||||
let now = new Date();
|
||||
let delta = now.getTime() - lastTime;
|
||||
timeSpent += delta;
|
||||
lodStatsTimer += delta;
|
||||
|
||||
if ((counter += delta) >= Config.FPS_UPDATE_INTERVAL) {
|
||||
counter = 0;
|
||||
if (fpsDisplay) {
|
||||
@@ -155,62 +159,38 @@ function drawScene() {
|
||||
}
|
||||
fps = 0;
|
||||
}
|
||||
lastTime = now.getTime();
|
||||
// Two Rendering passes. The first one generates a perlin noise
|
||||
// texture. Second one uses the textur for vertex displacement
|
||||
// of a grid representing the water surface.
|
||||
|
||||
//--- First render pass -> Perlin Noise (it updates the perlin noise texture)
|
||||
{
|
||||
gl.bindFramebuffer(gl.FRAMEBUFFER, perlinNoiseFBO);
|
||||
gl.viewport(0, 0, perlinNoiseFBOWidth, perlinNoiseFBOHeight);
|
||||
|
||||
//Clear buffer content
|
||||
gl.clearColor(1.0, 1.0, 1.0, 1);
|
||||
gl.clear(gl.COLOR_BUFFER_BIT); //No depth buffer
|
||||
|
||||
//draw a fullscreen quad
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, VBO);
|
||||
|
||||
// There are 7 floating-point values per vertex
|
||||
let stride = 5 * Float32Array.BYTES_PER_ELEMENT;
|
||||
|
||||
// Set up position stream
|
||||
gl.vertexAttribPointer(0, 3, gl.FLOAT, false, stride, 0);
|
||||
gl.enableVertexAttribArray(0);
|
||||
gl.vertexAttribPointer(1, 2, gl.FLOAT, false, stride, 3 * Float32Array.BYTES_PER_ELEMENT);
|
||||
gl.enableVertexAttribArray(1);
|
||||
|
||||
gl.useProgram(perlinNoiseProgram);
|
||||
let uTime = gl.getUniformLocation(<WebGLProgram>perlinNoiseProgram, "uTime");
|
||||
gl.uniform1f(uTime, timeSpent);
|
||||
gl.drawArrays(gl.TRIANGLES, 0, 6); // Draw fullscreen quad
|
||||
|
||||
// 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();
|
||||
// Single render pass with Gerstner waves computed in vertex shader
|
||||
|
||||
//--- Second render pass -> Geomtry with displacement by perlin noise texture ---
|
||||
//--- Render pass -> Ocean with Gerstner wave displacement ---
|
||||
{
|
||||
gl.bindFramebuffer(gl.FRAMEBUFFER, null); //Bind default framebuffer
|
||||
gl.viewport(0, 0, viewportWidth, viewportHeight);
|
||||
|
||||
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
||||
|
||||
gl.activeTexture(gl.TEXTURE0); //Binds the texture to 0
|
||||
gl.bindTexture(gl.TEXTURE_2D, textureFBO);
|
||||
|
||||
var projection = mat4.create();
|
||||
mat4.identity(projection);
|
||||
mat4.perspective(projection, Config.FOV, viewportWidth / viewportHeight, Config.NEAR_PLANE, Config.FAR_PLANE); //projection mode should actually be camera specific
|
||||
mat4.perspective(projection, Config.FOV, viewportWidth / viewportHeight, Config.NEAR_PLANE, Config.FAR_PLANE);
|
||||
|
||||
camera.setOffset(Config.CAMERA_DEFAULT_OFFSET + keyboardZoom);
|
||||
camera.setRotationX((curRotX += mouseYVel * Config.MOUSE_SENSITIVITY + keyboardRotationX));
|
||||
camera.setRotationY((curRotY += mouseXVel * Config.MOUSE_SENSITIVITY + keyboardRotationY));
|
||||
var view = camera.getViewMatrix();
|
||||
|
||||
// Update LOD based on camera position
|
||||
oceanLOD.updateLOD(gl, camera.pos);
|
||||
|
||||
var model = mat4.create();
|
||||
mat4.identity(model);
|
||||
let translationCentering = vec3.create();
|
||||
vec3.set(translationCentering, -0.5, -0.5, 0.0);
|
||||
mat4.translate(model, model, translationCentering); //1. First Center the Surface in the origin.
|
||||
// No centering needed - grids are already positioned correctly in world space
|
||||
|
||||
gl.useProgram(defaultProgram);
|
||||
let view_loc = gl.getUniformLocation(<WebGLProgram>defaultProgram, "view");
|
||||
@@ -221,11 +201,9 @@ function drawScene() {
|
||||
gl.uniformMatrix4fv(projection_loc, false, projection);
|
||||
let eye_loc = gl.getUniformLocation(<WebGLProgram>defaultProgram, "eyePos");
|
||||
gl.uniform3fv(eye_loc, camera.pos);
|
||||
//let uTime_loc = gl.getUniformLocation(<WebGLProgram>defaultProgram, "uTime");
|
||||
//gl.uniform1f(uTime_loc, timeSpent);
|
||||
let displacementMap_loc = gl.getUniformLocation(<WebGLProgram>defaultProgram, "displace_map");
|
||||
gl.uniform1i(displacementMap_loc, 0); //Get texture from slot 0
|
||||
oceanGrid.draw(gl);
|
||||
let uTime_loc = gl.getUniformLocation(<WebGLProgram>defaultProgram, "uTime");
|
||||
gl.uniform1f(uTime_loc, timeSpent);
|
||||
oceanLOD.draw(gl, wireframeMode);
|
||||
}
|
||||
requestAnimationFrame(drawScene);
|
||||
}
|
||||
@@ -317,13 +295,24 @@ function main() {
|
||||
window.addEventListener('resize', () => {
|
||||
updateCanvasSize(canvas);
|
||||
});
|
||||
|
||||
// Wireframe toggle handler
|
||||
window.addEventListener('toggleWireframe', () => {
|
||||
wireframeMode = !wireframeMode;
|
||||
const wireframeBtn = document.getElementById('wireframe-toggle');
|
||||
if (wireframeBtn) {
|
||||
wireframeBtn.textContent = `Wireframe: ${wireframeMode ? 'ON' : 'OFF'}`;
|
||||
}
|
||||
console.log(`Wireframe mode: ${wireframeMode ? 'ON' : 'OFF'}`);
|
||||
});
|
||||
|
||||
initShaders();
|
||||
initGeometry();
|
||||
initFBO();
|
||||
|
||||
oceanGrid = new Grid(Config.GRID_SIZE);
|
||||
oceanGrid.initVAO(gl);
|
||||
oceanLOD = new OceanLOD();
|
||||
oceanLOD.initVAO(gl);
|
||||
console.log(`Ocean LOD initialized with ${oceanLOD.getGridCount()} patches`);
|
||||
|
||||
camera = new Camera();
|
||||
//Check if any errors apeared during init.
|
||||
|
||||
Reference in New Issue
Block a user