mirror of
https://github.com/PavelDoGreat/WebGL-Fluid-Simulation.git
synced 2025-10-04 01:41:53 +02:00
vorticity + somethings
This commit is contained in:
169
script.js
169
script.js
@@ -2,26 +2,20 @@
|
||||
'use strict';
|
||||
|
||||
const canvas = document.getElementsByTagName('canvas')[0];
|
||||
const gl = canvas.getContext('webgl', { alpha: false, preserveDrawingBuffer: true });
|
||||
const gl = canvas.getContext('webgl', { alpha: false, preserveDrawingBuffer: false, depth: false, stencil: false });
|
||||
|
||||
if (!gl.getExtension("OES_texture_float")) {
|
||||
console.log("does not support OES_texture_float");
|
||||
}
|
||||
|
||||
const support_linear_float = gl.getExtension("OES_texture_float_linear");
|
||||
if (!support_linear_float) {
|
||||
console.log("does not support OES_texture_float_linear");
|
||||
}
|
||||
const halfFloat = gl.getExtension('OES_texture_half_float');
|
||||
const support_linear_float = gl.getExtension('OES_texture_half_float_linear');
|
||||
|
||||
resizeCanvas();
|
||||
|
||||
const TEXTURE_DOWNSAMPLE = 2;
|
||||
const TEXTURE_WIDTH = gl.drawingBufferWidth >> TEXTURE_DOWNSAMPLE;
|
||||
const TEXTURE_HEIGHT = gl.drawingBufferHeight >> TEXTURE_DOWNSAMPLE;
|
||||
const CELL_SIZE = 1.0;
|
||||
const DENSITY_DISSIPATION = 0.99;
|
||||
const VELOCITY_DISSIPATION = 0.999;
|
||||
const SPLAT_RADIUS = 0.001;
|
||||
const DENSITY_DISSIPATION = 0.98;
|
||||
const VELOCITY_DISSIPATION = 0.99;
|
||||
const SPLAT_RADIUS = 0.005;
|
||||
const CURL = 30;
|
||||
const PRESSURE_ITERATIONS = 20;
|
||||
|
||||
class GLProgram {
|
||||
@@ -62,6 +56,8 @@ function compileShader (type, source) {
|
||||
};
|
||||
|
||||
const baseVertexShader = compileShader(gl.VERTEX_SHADER, `
|
||||
precision mediump float;
|
||||
|
||||
attribute vec2 aPosition;
|
||||
varying vec2 vUv;
|
||||
varying vec2 vL;
|
||||
@@ -76,15 +72,18 @@ const baseVertexShader = compileShader(gl.VERTEX_SHADER, `
|
||||
vR = vUv + vec2(texelSize.x, 0.0);
|
||||
vT = vUv + vec2(0.0, texelSize.y);
|
||||
vB = vUv - vec2(0.0, texelSize.y);
|
||||
|
||||
gl_Position = vec4(aPosition, 0.0, 1.0);
|
||||
}
|
||||
`);
|
||||
|
||||
const displayShader = compileShader(gl.FRAGMENT_SHADER, `
|
||||
precision highp float;
|
||||
precision mediump float;
|
||||
|
||||
varying vec2 vUv;
|
||||
varying vec2 vL;
|
||||
varying vec2 vR;
|
||||
varying vec2 vT;
|
||||
varying vec2 vB;
|
||||
uniform sampler2D uTexture;
|
||||
|
||||
void main () {
|
||||
@@ -93,7 +92,7 @@ const displayShader = compileShader(gl.FRAGMENT_SHADER, `
|
||||
`);
|
||||
|
||||
const initDensityShader = compileShader(gl.FRAGMENT_SHADER, `
|
||||
precision highp float;
|
||||
precision mediump float;
|
||||
|
||||
varying vec2 vUv;
|
||||
|
||||
@@ -104,7 +103,7 @@ const initDensityShader = compileShader(gl.FRAGMENT_SHADER, `
|
||||
`);
|
||||
|
||||
const initVelocityShader = compileShader(gl.FRAGMENT_SHADER, `
|
||||
precision highp float;
|
||||
precision mediump float;
|
||||
|
||||
varying vec2 vUv;
|
||||
|
||||
@@ -114,7 +113,7 @@ const initVelocityShader = compileShader(gl.FRAGMENT_SHADER, `
|
||||
`);
|
||||
|
||||
const splatShader = compileShader(gl.FRAGMENT_SHADER, `
|
||||
precision highp float;
|
||||
precision mediump float;
|
||||
|
||||
varying vec2 vUv;
|
||||
uniform sampler2D uTarget;
|
||||
@@ -133,13 +132,12 @@ const splatShader = compileShader(gl.FRAGMENT_SHADER, `
|
||||
`);
|
||||
|
||||
const advectionManualFilteringShader = compileShader(gl.FRAGMENT_SHADER, `
|
||||
precision highp float;
|
||||
precision mediump float;
|
||||
|
||||
varying vec2 vUv;
|
||||
uniform sampler2D uVelocity;
|
||||
uniform sampler2D uSource;
|
||||
uniform vec2 texelSize;
|
||||
uniform float rdx;
|
||||
uniform float dt;
|
||||
uniform float dissipation;
|
||||
|
||||
@@ -157,31 +155,30 @@ const advectionManualFilteringShader = compileShader(gl.FRAGMENT_SHADER, `
|
||||
}
|
||||
|
||||
void main () {
|
||||
vec2 coord = gl_FragCoord.xy - rdx * dt * texture2D(uVelocity, vUv).xy;
|
||||
vec2 coord = gl_FragCoord.xy - dt * texture2D(uVelocity, vUv).xy;
|
||||
gl_FragColor = dissipation * bilerp(uSource, coord);
|
||||
gl_FragColor.a = 1.0;
|
||||
}
|
||||
`);
|
||||
|
||||
const advectionShader = compileShader(gl.FRAGMENT_SHADER, `
|
||||
precision highp float;
|
||||
precision mediump float;
|
||||
|
||||
varying vec2 vUv;
|
||||
uniform sampler2D uVelocity;
|
||||
uniform sampler2D uSource;
|
||||
uniform vec2 texelSize;
|
||||
uniform float rdx;
|
||||
uniform float dt;
|
||||
uniform float dissipation;
|
||||
|
||||
void main () {
|
||||
vec2 coord = vUv - rdx * dt * texture2D(uVelocity, vUv).xy * texelSize;
|
||||
vec2 coord = vUv - dt * texture2D(uVelocity, vUv).xy * texelSize;
|
||||
gl_FragColor = dissipation * texture2D(uSource, coord);
|
||||
}
|
||||
`);
|
||||
|
||||
const divergenceShader = compileShader(gl.FRAGMENT_SHADER, `
|
||||
precision highp float;
|
||||
precision mediump float;
|
||||
|
||||
varying vec2 vUv;
|
||||
varying vec2 vL;
|
||||
@@ -189,7 +186,6 @@ const divergenceShader = compileShader(gl.FRAGMENT_SHADER, `
|
||||
varying vec2 vT;
|
||||
varying vec2 vB;
|
||||
uniform sampler2D uVelocity;
|
||||
uniform float halfrdx;
|
||||
|
||||
vec2 sampleVelocity (in vec2 uv) {
|
||||
vec2 multiplier = vec2(1.0, 1.0);
|
||||
@@ -201,17 +197,67 @@ const divergenceShader = compileShader(gl.FRAGMENT_SHADER, `
|
||||
}
|
||||
|
||||
void main () {
|
||||
vec2 L = sampleVelocity(vL);
|
||||
vec2 R = sampleVelocity(vR);
|
||||
vec2 T = sampleVelocity(vT);
|
||||
vec2 B = sampleVelocity(vB);
|
||||
float div = halfrdx * (R.x - L.x + T.y - B.y);
|
||||
float L = sampleVelocity(vL).x;
|
||||
float R = sampleVelocity(vR).x;
|
||||
float T = sampleVelocity(vT).y;
|
||||
float B = sampleVelocity(vB).y;
|
||||
float div = 0.5 * (R - L + T - B);
|
||||
gl_FragColor = vec4(div, 0.0, 0.0, 1.0);
|
||||
}
|
||||
`);
|
||||
|
||||
const curlShader = compileShader(gl.FRAGMENT_SHADER, `
|
||||
precision mediump float;
|
||||
|
||||
varying vec2 vUv;
|
||||
varying vec2 vL;
|
||||
varying vec2 vR;
|
||||
varying vec2 vT;
|
||||
varying vec2 vB;
|
||||
uniform sampler2D uVelocity;
|
||||
|
||||
void main () {
|
||||
float L = texture2D(uVelocity, vL).y;
|
||||
float R = texture2D(uVelocity, vR).y;
|
||||
float T = texture2D(uVelocity, vT).x;
|
||||
float B = texture2D(uVelocity, vB).x;
|
||||
float vorticity = 0.5 * (R - L - T + B);
|
||||
gl_FragColor = vec4(vorticity, 0.0, 0.0, 1.0);
|
||||
}
|
||||
`);
|
||||
|
||||
const vorticityShader = compileShader(gl.FRAGMENT_SHADER, `
|
||||
precision mediump float;
|
||||
|
||||
varying vec2 vUv;
|
||||
varying vec2 vL;
|
||||
varying vec2 vR;
|
||||
varying vec2 vT;
|
||||
varying vec2 vB;
|
||||
uniform sampler2D uVelocity;
|
||||
uniform sampler2D uCurl;
|
||||
uniform float curl;
|
||||
uniform float dt;
|
||||
|
||||
void main () {
|
||||
float L = texture2D(uCurl, vL).y;
|
||||
float R = texture2D(uCurl, vR).y;
|
||||
float T = texture2D(uCurl, vT).x;
|
||||
float B = texture2D(uCurl, vB).x;
|
||||
float C = texture2D(uCurl, vUv).x;
|
||||
|
||||
vec2 force = 0.5 * vec2(abs(T) - abs(B), abs(R) - abs(L));
|
||||
float lengthSquared = max(0.0001, dot(force, force));
|
||||
force *= inversesqrt(lengthSquared) * curl * C;
|
||||
force.y *= -1.0;
|
||||
|
||||
vec2 vel = texture2D(uVelocity, vUv).xy;
|
||||
gl_FragColor = vec4(vel + force * dt, 0.0, 1.0);
|
||||
}
|
||||
`);
|
||||
|
||||
const pressureShader = compileShader(gl.FRAGMENT_SHADER, `
|
||||
precision highp float;
|
||||
precision mediump float;
|
||||
|
||||
varying vec2 vUv;
|
||||
varying vec2 vL;
|
||||
@@ -220,7 +266,6 @@ const pressureShader = compileShader(gl.FRAGMENT_SHADER, `
|
||||
varying vec2 vB;
|
||||
uniform sampler2D uPressure;
|
||||
uniform sampler2D uDivergence;
|
||||
uniform float alpha;
|
||||
|
||||
vec2 boundary (in vec2 uv) {
|
||||
uv = min(max(uv, 0.0), 1.0);
|
||||
@@ -232,14 +277,15 @@ const pressureShader = compileShader(gl.FRAGMENT_SHADER, `
|
||||
float R = texture2D(uPressure, boundary(vR)).x;
|
||||
float T = texture2D(uPressure, boundary(vT)).x;
|
||||
float B = texture2D(uPressure, boundary(vB)).x;
|
||||
float C = texture2D(uPressure, vUv).x;
|
||||
float divergence = texture2D(uDivergence, vUv).x;
|
||||
float pressure = (L + R + B + T + alpha * divergence) * .25;
|
||||
float pressure = (L + R + B + T - divergence) * 0.25;
|
||||
gl_FragColor = vec4(pressure, 0.0, 0.0, 1.0);
|
||||
}
|
||||
`);
|
||||
|
||||
const gradientSubtractShader = compileShader(gl.FRAGMENT_SHADER, `
|
||||
precision highp float;
|
||||
precision mediump float;
|
||||
|
||||
varying vec2 vUv;
|
||||
varying vec2 vL;
|
||||
@@ -248,7 +294,6 @@ const gradientSubtractShader = compileShader(gl.FRAGMENT_SHADER, `
|
||||
varying vec2 vB;
|
||||
uniform sampler2D uPressure;
|
||||
uniform sampler2D uVelocity;
|
||||
uniform float halfrdx;
|
||||
|
||||
vec2 boundary (in vec2 uv) {
|
||||
uv = min(max(uv, 0.0), 1.0);
|
||||
@@ -261,7 +306,7 @@ const gradientSubtractShader = compileShader(gl.FRAGMENT_SHADER, `
|
||||
float T = texture2D(uPressure, boundary(vT)).x;
|
||||
float B = texture2D(uPressure, boundary(vB)).x;
|
||||
vec2 velocity = texture2D(uVelocity, vUv).xy;
|
||||
velocity.xy -= halfrdx * vec2(R - L, T - B);
|
||||
velocity.xy -= vec2(R - L, T - B);
|
||||
gl_FragColor = vec4(velocity, 0.0, 1.0);
|
||||
}
|
||||
`);
|
||||
@@ -287,16 +332,16 @@ function clear (target) {
|
||||
}
|
||||
|
||||
let texId = -1;
|
||||
function createFBO (width, height, format, type) {
|
||||
function createFBO (width, height, format, type, param) {
|
||||
texId++;
|
||||
gl.activeTexture(gl.TEXTURE0 + texId);
|
||||
var texture = gl.createTexture();
|
||||
gl.bindTexture(gl.TEXTURE_2D, texture);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, type);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, type);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, param);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, param);
|
||||
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.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, format, null);
|
||||
gl.texImage2D(gl.TEXTURE_2D, 0, format, width, height, 0, format, type, null);
|
||||
|
||||
var fbo = gl.createFramebuffer();
|
||||
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
|
||||
@@ -308,9 +353,9 @@ function createFBO (width, height, format, type) {
|
||||
return [texture, fbo, texId];
|
||||
}
|
||||
|
||||
function createDoubleFBO (width, height, format, type) {
|
||||
let fbo1 = createFBO(width, height, format, type);
|
||||
let fbo2 = createFBO(width, height, format, type);
|
||||
function createDoubleFBO (width, height, format, type, param) {
|
||||
let fbo1 = createFBO(width, height, format, type, param);
|
||||
let fbo2 = createFBO(width, height, format, type, param);
|
||||
|
||||
return {
|
||||
get first () {
|
||||
@@ -327,18 +372,20 @@ function createDoubleFBO (width, height, format, type) {
|
||||
}
|
||||
}
|
||||
|
||||
let density = createDoubleFBO(TEXTURE_WIDTH, TEXTURE_HEIGHT, gl.FLOAT, support_linear_float ? gl.LINEAR : gl.NEAREST);
|
||||
let velocity = createDoubleFBO(TEXTURE_WIDTH, TEXTURE_HEIGHT, gl.FLOAT, support_linear_float ? gl.LINEAR : gl.NEAREST);
|
||||
let divergence = createFBO(TEXTURE_WIDTH, TEXTURE_HEIGHT, gl.FLOAT, gl.NEAREST);
|
||||
let pressure = createDoubleFBO(TEXTURE_WIDTH, TEXTURE_HEIGHT, gl.FLOAT, gl.NEAREST);
|
||||
let density = createDoubleFBO(TEXTURE_WIDTH, TEXTURE_HEIGHT, gl.RGBA, halfFloat.HALF_FLOAT_OES, support_linear_float ? gl.LINEAR : gl.NEAREST);
|
||||
let velocity = createDoubleFBO(TEXTURE_WIDTH, TEXTURE_HEIGHT, gl.RGBA, halfFloat.HALF_FLOAT_OES, support_linear_float ? gl.LINEAR : gl.NEAREST);
|
||||
let divergence = createFBO (TEXTURE_WIDTH, TEXTURE_HEIGHT, gl.RGBA, halfFloat.HALF_FLOAT_OES, gl.NEAREST);
|
||||
let curl = createFBO (TEXTURE_WIDTH, TEXTURE_HEIGHT, gl.RGBA, halfFloat.HALF_FLOAT_OES, gl.NEAREST);
|
||||
let pressure = createDoubleFBO(TEXTURE_WIDTH, TEXTURE_HEIGHT, gl.RGBA, halfFloat.HALF_FLOAT_OES, gl.NEAREST);
|
||||
|
||||
const displayProgram = new GLProgram(baseVertexShader, displayShader);
|
||||
const splatProgram = new GLProgram(baseVertexShader, splatShader);
|
||||
const initDensityProgram = new GLProgram(baseVertexShader, initDensityShader);
|
||||
const initVelocityProgram = new GLProgram(baseVertexShader, initVelocityShader);
|
||||
|
||||
const advectionProgram = new GLProgram(baseVertexShader, support_linear_float ? advectionShader : advectionManualFilteringShader);
|
||||
const divergenceProgram = new GLProgram(baseVertexShader, divergenceShader);
|
||||
const curlProgram = new GLProgram(baseVertexShader, curlShader);
|
||||
const vorticityProgram = new GLProgram(baseVertexShader, vorticityShader);
|
||||
const pressureProgram = new GLProgram(baseVertexShader, pressureShader);
|
||||
const gradienSubtractProgram = new GLProgram(baseVertexShader, gradientSubtractShader);
|
||||
|
||||
@@ -368,8 +415,7 @@ function Update () {
|
||||
gl.uniform2f(advectionProgram.uniforms.texelSize, 1.0 / TEXTURE_WIDTH, 1.0 / TEXTURE_HEIGHT);
|
||||
gl.uniform1i(advectionProgram.uniforms.uVelocity, velocity.first[2]);
|
||||
gl.uniform1i(advectionProgram.uniforms.uSource, velocity.first[2]);
|
||||
gl.uniform1f(advectionProgram.uniforms.rdx, 1.0 / CELL_SIZE);
|
||||
gl.uniform1f(advectionProgram.uniforms.dt, 0.16);
|
||||
gl.uniform1f(advectionProgram.uniforms.dt, 0.016);
|
||||
gl.uniform1f(advectionProgram.uniforms.dissipation, VELOCITY_DISSIPATION);
|
||||
blit(velocity.second[1]);
|
||||
velocity.swap();
|
||||
@@ -392,22 +438,34 @@ function Update () {
|
||||
velocity.swap();
|
||||
|
||||
gl.uniform1i(splatProgram.uniforms.uTarget, density.first[2]);
|
||||
gl.uniform3f(splatProgram.uniforms.color, pointer.color[0] * 0.2, pointer.color[1] * 0.2, pointer.color[2] * 0.2);
|
||||
gl.uniform3f(splatProgram.uniforms.color, pointer.color[0] * 0.3, pointer.color[1] * 0.3, pointer.color[2] * 0.3);
|
||||
blit(density.second[1]);
|
||||
density.swap();
|
||||
}
|
||||
|
||||
curlProgram.bind();
|
||||
gl.uniform2f(curlProgram.uniforms.texelSize, 1.0 / TEXTURE_WIDTH, 1.0 / TEXTURE_HEIGHT);
|
||||
gl.uniform1i(curlProgram.uniforms.uVelocity, velocity.first[2]);
|
||||
blit(curl[1]);
|
||||
|
||||
vorticityProgram.bind();
|
||||
gl.uniform2f(vorticityProgram.uniforms.texelSize, 1.0 / TEXTURE_WIDTH, 1.0 / TEXTURE_HEIGHT);
|
||||
gl.uniform1i(vorticityProgram.uniforms.uVelocity, velocity.first[2]);
|
||||
gl.uniform1i(vorticityProgram.uniforms.uCurl, curl[2]);
|
||||
gl.uniform1f(vorticityProgram.uniforms.curl, CURL);
|
||||
gl.uniform1f(vorticityProgram.uniforms.dt, 0.016);
|
||||
blit(velocity.second[1]);
|
||||
velocity.swap();
|
||||
|
||||
divergenceProgram.bind();
|
||||
gl.uniform2f(divergenceProgram.uniforms.texelSize, 1.0 / TEXTURE_WIDTH, 1.0 / TEXTURE_HEIGHT);
|
||||
gl.uniform1i(divergenceProgram.uniforms.uVelocity, velocity.first[2]);
|
||||
gl.uniform1f(divergenceProgram.uniforms.halfrdx, 0.5 / CELL_SIZE);
|
||||
blit(divergence[1]);
|
||||
|
||||
clear(pressure.first[1]);
|
||||
pressureProgram.bind();
|
||||
gl.uniform2f(pressureProgram.uniforms.texelSize, 1.0 / TEXTURE_WIDTH, 1.0 / TEXTURE_HEIGHT);
|
||||
gl.uniform1i(pressureProgram.uniforms.uDivergence, divergence[2]);
|
||||
gl.uniform1f(pressureProgram.uniforms.alpha, -CELL_SIZE * CELL_SIZE);
|
||||
for (let i = 0; i < PRESSURE_ITERATIONS; i++) {
|
||||
gl.uniform1i(pressureProgram.uniforms.uPressure, pressure.first[2]);
|
||||
blit(pressure.second[1]);
|
||||
@@ -418,7 +476,6 @@ function Update () {
|
||||
gl.uniform2f(gradienSubtractProgram.uniforms.texelSize, 1.0 / TEXTURE_WIDTH, 1.0 / TEXTURE_HEIGHT);
|
||||
gl.uniform1i(gradienSubtractProgram.uniforms.uPressure, pressure.first[2]);
|
||||
gl.uniform1i(gradienSubtractProgram.uniforms.uVelocity, velocity.first[2]);
|
||||
gl.uniform1f(gradienSubtractProgram.uniforms.halfrdx, 0.5 / CELL_SIZE);
|
||||
blit(velocity.second[1]);
|
||||
velocity.swap();
|
||||
|
||||
@@ -459,7 +516,7 @@ canvas.addEventListener('touchmove', (e) => {
|
||||
});
|
||||
|
||||
function clampDelta (delta) {
|
||||
return Math.min(Math.max(delta, -CELL_SIZE), CELL_SIZE);
|
||||
return delta * 10;//Math.min(Math.max(delta, -CELL_SIZE), CELL_SIZE);
|
||||
}
|
||||
|
||||
canvas.addEventListener('mousedown', onPointerDown);
|
||||
|
Reference in New Issue
Block a user