vorticity + somethings

This commit is contained in:
Pavel Dobryakov
2017-08-20 19:10:17 +03:00
parent 2e0d685452
commit 7eb6a67c0c
2 changed files with 113 additions and 57 deletions

View File

@@ -7,7 +7,6 @@
}
canvas {
position: absolute;
width: 100%;
height: 100%;
}

169
script.js
View File

@@ -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);