Graphics Engineering

Fluid Physics in Three.js: Real-time Water Simulation for Web

Master real-time fluid simulations in the browser. Learn how to use Three.js and GPGPU techniques to create stunning water effects in 2026.

Sachin Sharma
Sachin SharmaCreator
Apr 20, 2026
2 min read
Fluid Physics in Three.js: Real-time Water Simulation for Web
Featured Resource
Quick Overview

Master real-time fluid simulations in the browser. Learn how to use Three.js and GPGPU techniques to create stunning water effects in 2026.

Fluid Physics in Three.js: Real-time Water Simulation for Web

In 2026, the delta between native gaming and web visuals is disappearing. One of the most requested features for high-end web experiences is realistic, interactive fluid physics.

Today, we'll explore how to build a Real-time Water Simulation that runs at 120fps using Three.js and GPGPU (General-Purpose GPU compute).

Why GPGPU?

Traditional CPU-based physics are too slow for millions of water particles. By using GPGPU, we use the GPU's thousands of cores to calculate the position and velocity of every particle simultaneously.

The Navier-Stokes Approach

To simulate fluid, we follow a simplified version of the Navier-Stokes equations:

  1. 2.
    Advection: Move the fluid velocity along the fluid itself.
  2. 4.
    Diffusion: Spread high-velocity areas to low-velocity areas (viscosity).
  3. 6.
    Pressure: Ensure the fluid is incompressible (it shouldn't "clump").

Implementation: The GPUComputeManager

In Three.js, we use the GPUComputationRenderer utility to manage our simulation textures.

javascript
import { GPUComputationRenderer } from 'three/examples/jsm/misc/GPUComputationRenderer.js'; const gpuCompute = new GPUComputationRenderer(WIDTH, WIDTH, renderer); // Create textures for position and velocity const dtPosition = gpuCompute.createTexture(); const dtVelocity = gpuCompute.createTexture(); // Add custom shaders for fluid math const velocityVariable = gpuCompute.addVariable('textureVelocity', velocityShader, dtVelocity); const positionVariable = gpuCompute.addVariable('texturePosition', positionShader, dtPosition); // Link variables gpuCompute.setVariableDependencies(velocityVariable, [positionVariable, velocityVariable]); gpuCompute.setVariableDependencies(positionVariable, [positionVariable, velocityVariable]); gpuCompute.init();

Shading the Surface: Refraction and Reflection

A simulation is nothing without a good shader. To make water look real, we need:

  • Fresnel Effect: Water is more reflective when viewed at a glancing angle.
  • Refraction: Light should bend as it passes through the water volume.
  • Caustics: Concentrated light patterns on the floor of the water body.
glsl
// Fragment Shader snippet for water surface void main() { vec3 normal = calculateNormal(vUv); vec3 viewDir = normalize(cameraPosition - vPosition); float fresnel = pow(1.0 - dot(normal, viewDir), 5.0); vec3 reflection = textureCube(envMap, reflect(-viewDir, normal)).rgb; vec3 refraction = texture2D(tDiffuse, vUv + normal.xy * 0.1).rgb; gl_FragColor = vec4(mix(refraction, reflection, fresnel), 1.0); }

Performance in 2026

With the widespread adoption of WebGPU, these simulations are becoming even more efficient. However, the WebGL GPGPU approach remains the most compatible way to reach 99% of global users today.

Conclusion

Adding fluid physics to your portfolio isn't just a technical challenge; it's an aesthetic one. It brings a sense of life and interactivity to the digital world that static 3D models can never achieve. Ready to take the plunge?

Sachin Sharma

Sachin Sharma

Software Developer & Mobile Engineer

Building digital experiences at the intersection of design and code. Sharing weekly insights on engineering, productivity, and the future of tech.