Newer
Older
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Fluid Simulation</title>
<link rel="stylesheet" type="text/css" href="dependencies/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="dependencies/flat-ui.min.css">
<link rel="stylesheet" type="text/css" href="main.css">
<script id="2d-vertex-shader" type="x-shader/x-vertex">
attribute vec2 a_position;
void main() {
gl_Position = vec4(a_position, 0, 1);
}
</script>
<script id="2d-render-shader" type="x-shader/x-fragment">
precision mediump float;
gl_FragColor = vec4(texture2D(u_material, fragCoord/u_textureSize).x, 0, 1, 1);
<script id="diffuseShader" type="x-shader/x-fragment">
precision mediump float;
uniform sampler2D u_material;
uniform vec2 u_textureSize;
uniform float u_alpha;
uniform float u_reciprocalBeta;
void main() {
vec2 fragCoord = gl_FragCoord.xy;
vec2 currentState = texture2D(u_material, fragCoord/u_textureSize).xy;
//implicitly solve diffusion via jacobi iteration
vec2 n = texture2D(u_material, (fragCoord+vec2(0.0, 1.0))/u_textureSize).xy;
vec2 s = texture2D(u_material, (fragCoord+vec2(0.0, -1.0))/u_textureSize).xy;
vec2 e = texture2D(u_material, (fragCoord+vec2(1.0, 0.0))/u_textureSize).xy;
vec2 w = texture2D(u_material, (fragCoord+vec2(-1.0, 0.0))/u_textureSize).xy;
vec2 nextState = (n + s + e + w + u_alpha * currentState) * u_reciprocalBeta;
gl_FragColor = vec4(nextState, 0, 0);
}
</script>
<script id="advectShader" type="x-shader/x-fragment">
uniform sampler2D u_velocity;
uniform sampler2D u_material;
vec2 currentVelocity = texture2D(u_velocity, fragCoord/u_textureSize).xy;
if (length(currentVelocity) == 0.0) {//no velocity
gl_FragColor = vec4(texture2D(u_material, fragCoord/u_textureSize).x, 0, 0, 0);
return;
}
vec2 pxCenter = vec2(0.5, 0.5);
if (pos.x < 0.0 || pos.x >= u_textureSize.x-1.0 || pos.y < 0.0 || pos.y >= u_textureSize.y-1.0){
//boundary
gl_FragColor = vec4(0);
return;
}
//bilinear interp between nearest cells
vec2 ceiled = ceil(pos);
vec2 floored = floor(pos);
float n = texture2D(u_material, (ceiled+pxCenter)/u_textureSize).x;//actually ne
float s = texture2D(u_material, (floored+pxCenter)/u_textureSize).x;//actually sw
if (ceiled.x != floored.x){
float se = texture2D(u_material, (vec2(ceiled.x, floored.y)+pxCenter)/u_textureSize).x;
float nw = texture2D(u_material, (vec2(floored.x, ceiled.y)+pxCenter)/u_textureSize).x;
n = n*(pos.x-floored.x) + nw*(ceiled.x-pos.x);
s = se*(pos.x-floored.x) + s*(ceiled.x-pos.x);
}
float materialVal = n;
if (ceiled.y != floored.y){
materialVal = n*(pos.y-floored.y) + s*(ceiled.y-pos.y);
}
gl_FragColor = vec4(materialVal, 0, 0, 0);
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
}
</script>
<script id="2d-fragment-shader" type="x-shader/x-fragment">
precision mediump float;
#define M_PI 3.1415926535897932384626433832795
//texture array
uniform sampler2D u_image;//u, v, --, -- = r, g, b, a
uniform vec2 u_textureSize;
uniform vec2 u_mouseCoord;
uniform float u_mouseEnable;
const float dt = 1.0;
void main() {
vec2 fragCoord = gl_FragCoord.xy;
vec2 currentState = texture2D(u_image, fragCoord/u_textureSize).xy;
float u = currentState.x;
float v = currentState.y;
vec2 n = texture2D(u_image, (fragCoord + vec2(0.0, 1.0))/u_textureSize).xy;//north
vec2 s = texture2D(u_image, (fragCoord + vec2(0.0, -1.0))/u_textureSize).xy;//south
vec2 e = texture2D(u_image, (fragCoord + vec2(-1.0, 0.0))/u_textureSize).xy;//east
vec2 w = texture2D(u_image, (fragCoord + vec2(1.0, 0.0))/u_textureSize).xy;//west
if (u_mouseEnable == 1.0){
vec2 pxDistFromMouse = (fragCoord - u_mouseCoord)*(fragCoord - u_mouseCoord);
float tol = 10.0;
if (length(pxDistFromMouse)<tol){
gl_FragColor = vec4(0.5, 0.35, 0, 1);
return;
}
}
gl_FragColor = vec4(0,0, 0, 1);
}
</script>
<script type="text/javascript" src="dependencies/jquery-3.1.0.min.js"></script>
<script type="text/javascript" src="dependencies/flat-ui.min.js"></script>
<script type="text/javascript" src="GLBoilerplate.js"></script>
<script type="text/javascript" src="GPUMath.js"></script>
<script type="text/javascript" src="main.js"></script>
</head>
<body>
<canvas id="glcanvas"></canvas>
<a href="#" id="about">?</a>
<div class="modal fade" id="aboutModal" tabindex="-1" role="dialog" aria-labelledby="basicModal" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-body">
<b>Fluid Simulation Shader</b><br/><br/>
<a href="https://pdfs.semanticscholar.org/84b8/c7b7eecf90ebd9d54a51544ca0f8ff93c137.pdf" target="_blank">Real-time ink simulation using a grid-particle method</a> - a method for real-time simulation of ink
in water using a coarse-grained fluid simulation with a particle simulation on top.<br/>
<a href="http://http.developer.nvidia.com/GPUGems/gpugems_ch38.html" target="_blank">Fast Fluid Dynamics Simulation on the GPU</a> - a very well written tutorial about programming the Navier-Stokes equations on a GPU.<br/>
<a href="http://www.dgp.toronto.edu/people/stam/reality/Research/pdf/ns.pdf" target="_blank">Stable Fluids</a> - a paper about stable numerical methods for evaluating Navier-Stokes on a discrete grid.<br/>
<br/>
By <a href="http://www.amandaghassaei.com/" target="_blank">Amanda Ghassaei</a>, code on <a href="https://github.com/amandaghassaei/FluidSimulation" target="_blank">Github</a>.