- No Accumulation Drift: Motion is calculated as a pure function of total elapsed time
y = f(t), not iterativey += dy. - Stateless Physics: The simulation can be paused, reversed, or scrubbed to any timestamp with bit-exact reproducibility.
- Artifact-Free Lighting: Normals are not approximated via finite differences (neighbor sampling).
-
Exact Math: The partial derivatives
$\partial y / \partial x$ and$\partial y / \partial z$ are computed analytically in the vertex shader to construct the exact tangent frame.
- Zero Runtime Branching: The
SurfaceEnginearchitecture switches betweenANALYTICandTEXTUREmodes using GLSL preprocessor defines (#define MODE_ANALYTIC). - Shader Recompilation: Changing modes triggers a material recompile, ensuring the GPU only executes code relevant to the active mode.
- Interpolation Engine: All physical parameters (amplitude and wavelength (frequency and angular velocity derived via dispersion), direction) are linearly interpolated (Lerped) over time.
- Visual Continuity: Changing presets results in a fluid morphing animation rather than a jarring snap.
- High Precision: Explicit
precision highp floatqualifiers in shaders prevent banding and vertex jitter on mobile GPUs.
This project demonstrates a rigorous engineering approach to procedurally animated surfaces, prioritizing determinism, physical correctness, and architectural extensibility.
The surface displacement is computed entirely in the vertex shader using harmonic wave equations. No noise, no random phase offsets, and no CPU-side geometry updates are used. Each wave component follows the standard travelling wave form:
where:
-
$A$ : amplitude -
$k$ : wave number ($2\pi / \lambda$ ) -
$\omega$ : angular frequency -
$t$ : deterministic elapsed time
Time is derived directly from clock.getElapsedTime() to ensure frame-rate independence and repeatability.
To keep motion physically meaningful, the model uses the deep-water dispersion relation:
with gravitational acceleration
- Long waves move slower
- Short waves move faster
- Phase velocity is not arbitrary
- Motion remains physically consistent
Users control Amplitude and Wavelength. Wave speed is derived from physics rather than manually tuned.
When multiple waves are combined:
- Amplitude Normalization: Amplitudes are normalized to prevent energy explosion.
-
Steepness Constraint: A steepness constraint is enforced:
$k \cdot A \le 0.4$ . This avoids unrealistic vertical folds and maintains stable surface behavior.
Surface normals are computed analytically from the derivatives of the wave equation. This ensures:
- Physically consistent lighting
- Stable specular highlights
- No shading artifacts from displaced geometry
The system is fully deterministic:
- No stochastic noise
- No accumulated time drift
- Same inputs always produce the same surface state
This implementation does not use FFT-based ocean spectra or Navier–Stokes fluid solvers. Those approaches are typically used for large-scale, fully dynamic fluid simulation, where:
- Energy spectra must be modeled statistically
- Wave interactions evolve over time
- State is propagated frame-to-frame using GPGPU
The goal of this system is different. Here, the focus is on Deterministic behavior, Analytic control, and Stable, geometry-driven displacement.
By using closed-form harmonic equations with deep-water dispersion:
- The system remains fully deterministic
- No simulation state is accumulated
- Performance stays stable at ~60 FPS
- Motion can be precisely controlled and reproduced
This makes the approach suitable for controlled real-time surface motion systems where predictability and stability are more important than full fluid simulation complexity.
SurfaceEngine.js: The core controller. Owns the material state, manages the simulation loop, and handles the transition logic.shaders/vertex.glsl: A modular shader with#ifdefguards for extensible displacement logic.main.js: Application entry point, handles bootstrapping and UI.
- Clone the repository
- Run a local server (Essential for loading shader files):
# Python 3 python -m http.server 8080 # Node.js npx http-server .
- Open Browser:
http://localhost:8080
- Engine Mode:
Analytic: Physics-based harmonic wave superposition.Texture: Placeholder for texture-driven/GPGPU heightfields.
- Presets:
Calm: Long wavelengths, low amplitude.Moderate: Balanced multi-directional sea state.Intense: Stormy, high-frequency chop.
- Stats: Real-time FPS monitoring.
The MODE_TEXTURE branch in vertex.glsl is designed to be easily replaced with:
- FFT Ocean Simulations: Sampling a frequency-domain texture.
- GPGPU Fluid Solvers: Reading from a ping-pong simulation buffer.
- Dynamic Ripple Solvers: Interactive water surfaces.
This project was developed with the assistance of modern AI tools (ChatGPT 5.2 and Gemini 3 Pro High).
