index.html 9.43 KB
Newer Older
amandaghassaei's avatar
setup  
amandaghassaei committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
<!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>

amandaghassaei's avatar
amandaghassaei committed
20 21 22 23 24 25 26 27 28 29 30
    <script id="boundaryShader" type="x-shader/x-fragment">
        precision mediump float;

        uniform sampler2D u_texture;
        uniform float u_scale;
        uniform vec2 u_textureSize;

        void main() {
            vec2 fragCoord = gl_FragCoord.xy;

            if (fragCoord.x < 1.0){
amandaghassaei's avatar
amandaghassaei committed
31 32 33 34 35 36 37 38 39 40
                gl_FragColor = u_scale*texture2D(u_texture, (fragCoord + vec2(1.0, 0.0))/u_textureSize);
                return;
            } else if (fragCoord.x >= u_textureSize.x-1.0){
                gl_FragColor = u_scale*texture2D(u_texture, (fragCoord + vec2(-1.0, 0.0))/u_textureSize);
                return;
            } else if (fragCoord.y < 1.0){
                gl_FragColor = u_scale*texture2D(u_texture, (fragCoord + vec2(0.0, 1.0))/u_textureSize);
                return;
            } else if (fragCoord.y >= u_textureSize.y-1.0){
                gl_FragColor = u_scale*texture2D(u_texture, (fragCoord + vec2(0.0, -1.0))/u_textureSize);
amandaghassaei's avatar
amandaghassaei committed
41 42 43 44 45 46 47
                return;
            }

            gl_FragColor = texture2D(u_texture, (fragCoord)/u_textureSize);
        }
    </script>

amandaghassaei's avatar
setup  
amandaghassaei committed
48 49 50
    <script id="2d-render-shader" type="x-shader/x-fragment">
        precision mediump float;

amandaghassaei's avatar
amandaghassaei committed
51
        uniform sampler2D u_material;
amandaghassaei's avatar
amandaghassaei committed
52
        uniform vec2 u_textureSize;
amandaghassaei's avatar
amandaghassaei committed
53 54

        void main() {
amandaghassaei's avatar
amandaghassaei committed
55
            vec2 fragCoord = gl_FragCoord.xy;
amandaghassaei's avatar
amandaghassaei committed
56
            gl_FragColor = vec4(texture2D(u_material, fragCoord/u_textureSize).x, 0, 1, 1);
amandaghassaei's avatar
amandaghassaei committed
57 58 59
        }
    </script>

amandaghassaei's avatar
amandaghassaei committed
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
    <script id="gradientSubtractionShader" type="x-shader/x-fragment">
        precision mediump float;

        uniform sampler2D u_velocity;
        uniform sampler2D u_pressure;

        uniform vec2 u_textureSize;

        uniform float u_const;

        void main() {

            vec2 fragCoord = gl_FragCoord.xy;

            vec2 currentVelocity = texture2D(u_velocity, fragCoord/u_textureSize).xy;

            float n = texture2D(u_pressure, (fragCoord+vec2(0.0, 1.0))/u_textureSize).x;
            float s = texture2D(u_pressure, (fragCoord+vec2(0.0, -1.0))/u_textureSize).x;
            float e = texture2D(u_pressure, (fragCoord+vec2(1.0, 0.0))/u_textureSize).x;
            float w = texture2D(u_pressure, (fragCoord+vec2(-1.0, 0.0))/u_textureSize).x;

            gl_FragColor = vec4(currentVelocity-u_const*vec2(e-w, n-s), 0, 0);
        }
    </script>

amandaghassaei's avatar
amandaghassaei committed
85 86 87 88 89 90 91
    <script id="divergenceShader" type="x-shader/x-fragment">
        precision mediump float;

        uniform sampler2D u_velocity;

        uniform vec2 u_textureSize;

amandaghassaei's avatar
amandaghassaei committed
92
        uniform float u_const;
amandaghassaei's avatar
amandaghassaei committed
93 94 95 96 97 98 99 100 101 102 103 104

        void main() {

            vec2 fragCoord = gl_FragCoord.xy;

            //finite difference formulation of divergence

            float n = texture2D(u_velocity, (fragCoord+vec2(0.0, 1.0))/u_textureSize).y;
            float s = texture2D(u_velocity, (fragCoord+vec2(0.0, -1.0))/u_textureSize).y;
            float e = texture2D(u_velocity, (fragCoord+vec2(1.0, 0.0))/u_textureSize).x;
            float w = texture2D(u_velocity, (fragCoord+vec2(-1.0, 0.0))/u_textureSize).x;

amandaghassaei's avatar
amandaghassaei committed
105
            float div = u_const*(e-w + n-s);
amandaghassaei's avatar
amandaghassaei committed
106
            gl_FragColor = vec4(div, 0, 0, 0);
amandaghassaei's avatar
amandaghassaei committed
107 108 109
        }
    </script>

amandaghassaei's avatar
force  
amandaghassaei committed
110 111 112 113 114 115 116 117 118 119 120
    <script id="forceShader" type="x-shader/x-fragment">
        precision mediump float;

        uniform sampler2D u_velocity;

        uniform vec2 u_textureSize;

        uniform vec2 u_mouseCoord;
        uniform vec2 u_mouseDir;
        uniform float u_mouseEnable;

amandaghassaei's avatar
scale  
amandaghassaei committed
121
        uniform float u_reciprocalRadius;
amandaghassaei's avatar
force  
amandaghassaei committed
122

amandaghassaei's avatar
scale  
amandaghassaei committed
123
        uniform float u_dt;
amandaghassaei's avatar
force  
amandaghassaei committed
124 125 126 127 128 129 130 131 132

        void main() {

            vec2 fragCoord = gl_FragCoord.xy;

            vec2 currentVelocity = texture2D(u_velocity, fragCoord/u_textureSize).xy;

            if (u_mouseEnable == 1.0){
                vec2 pxDist = fragCoord - u_mouseCoord;
amandaghassaei's avatar
scale  
amandaghassaei committed
133
                currentVelocity += u_mouseDir*u_dt*exp(-(pxDist.x*pxDist.x+pxDist.y*pxDist.y)*u_reciprocalRadius);
amandaghassaei's avatar
force  
amandaghassaei committed
134 135 136 137 138 139
            }

            gl_FragColor = vec4(currentVelocity, 0, 0);
        }
    </script>

amandaghassaei's avatar
amandaghassaei committed
140
    <script id="jacobiShader" type="x-shader/x-fragment">
amandaghassaei's avatar
amandaghassaei committed
141 142
        precision mediump float;

amandaghassaei's avatar
amandaghassaei committed
143 144
        uniform sampler2D u_b;
        uniform sampler2D u_x;
amandaghassaei's avatar
amandaghassaei committed
145 146 147 148 149 150 151 152 153 154

        uniform vec2 u_textureSize;

        uniform float u_alpha;
        uniform float u_reciprocalBeta;

        void main() {

            vec2 fragCoord = gl_FragCoord.xy;

amandaghassaei's avatar
amandaghassaei committed
155
            vec2 currentState = texture2D(u_b, fragCoord/u_textureSize).xy;
amandaghassaei's avatar
amandaghassaei committed
156 157 158

            //implicitly solve diffusion via jacobi iteration

amandaghassaei's avatar
amandaghassaei committed
159 160 161 162
            vec2 n = texture2D(u_x, (fragCoord+vec2(0.0, 1.0))/u_textureSize).xy;
            vec2 s = texture2D(u_x, (fragCoord+vec2(0.0, -1.0))/u_textureSize).xy;
            vec2 e = texture2D(u_x, (fragCoord+vec2(1.0, 0.0))/u_textureSize).xy;
            vec2 w = texture2D(u_x, (fragCoord+vec2(-1.0, 0.0))/u_textureSize).xy;
amandaghassaei's avatar
amandaghassaei committed
163 164 165 166 167

            vec2 nextState = (n + s + e + w + u_alpha * currentState) * u_reciprocalBeta;

            gl_FragColor = vec4(nextState, 0, 0);
        }
amandaghassaei's avatar
amandaghassaei committed
168
   </script>
amandaghassaei's avatar
amandaghassaei committed
169 170

    <script id="advectShader" type="x-shader/x-fragment">
amandaghassaei's avatar
amandaghassaei committed
171
        precision mediump float;
amandaghassaei's avatar
setup  
amandaghassaei committed
172

amandaghassaei's avatar
amandaghassaei committed
173 174
        uniform sampler2D u_velocity;
        uniform sampler2D u_material;
amandaghassaei's avatar
amandaghassaei committed
175

amandaghassaei's avatar
amandaghassaei committed
176
        uniform vec2 u_textureSize;
177
        uniform float u_scale;
amandaghassaei's avatar
amandaghassaei committed
178

amandaghassaei's avatar
amandaghassaei committed
179
        uniform float u_dt;
amandaghassaei's avatar
setup  
amandaghassaei committed
180

amandaghassaei's avatar
amandaghassaei committed
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
        vec2 bilinearInterp(vec2 pos, sampler2D texture, vec2 size){
            //bilinear interp between nearest cells

            vec2 pxCenter = vec2(0.5, 0.5);

            vec2 ceiled = ceil(pos);
            vec2 floored = floor(pos);

            vec2 n = texture2D(texture, (ceiled+pxCenter)/size).xy;//actually ne
            vec2 s = texture2D(texture, (floored+pxCenter)/size).xy;//actually sw
            if (ceiled.x != floored.x){
                vec2 se = texture2D(texture, (vec2(ceiled.x, floored.y)+pxCenter)/size).xy;
                vec2 nw = texture2D(texture, (vec2(floored.x, ceiled.y)+pxCenter)/size).xy;
                n = n*(pos.x-floored.x) + nw*(ceiled.x-pos.x);
                s = se*(pos.x-floored.x) + s*(ceiled.x-pos.x);
            }
            vec2 materialVal = n;
            if (ceiled.y != floored.y){
                materialVal = n*(pos.y-floored.y) + s*(ceiled.y-pos.y);
            }
            return materialVal;
        }

amandaghassaei's avatar
setup  
amandaghassaei committed
204
        void main() {
amandaghassaei's avatar
amandaghassaei committed
205

amandaghassaei's avatar
amandaghassaei committed
206
            vec2 fragCoord = gl_FragCoord.xy;
amandaghassaei's avatar
amandaghassaei committed
207

amandaghassaei's avatar
amandaghassaei committed
208 209 210 211
            vec2 pxCenter = vec2(0.5, 0.5);

            vec2 currentVelocity;
            if (u_scale == 1.0) currentVelocity = 1.0/u_scale*texture2D(u_velocity, fragCoord/u_textureSize).xy;
amandaghassaei's avatar
amandaghassaei committed
212 213 214
            else {
                currentVelocity = 1.0/u_scale*bilinearInterp((fragCoord-pxCenter)*u_scale, u_velocity, u_textureSize*u_scale);
            }
amandaghassaei's avatar
amandaghassaei committed
215 216

            //implicitly solve advection
amandaghassaei's avatar
amandaghassaei committed
217

amandaghassaei's avatar
amandaghassaei committed
218
            if (length(currentVelocity) == 0.0) {//no velocity
amandaghassaei's avatar
force  
amandaghassaei committed
219
                gl_FragColor = vec4(texture2D(u_material, fragCoord/u_textureSize).xy, 0, 0);
amandaghassaei's avatar
amandaghassaei committed
220 221 222
                return;
            }

amandaghassaei's avatar
amandaghassaei committed
223
            vec2 pos = fragCoord - pxCenter - u_dt*currentVelocity;
amandaghassaei's avatar
amandaghassaei committed
224

amandaghassaei's avatar
amandaghassaei committed
225 226
            vec2 materialVal;
            //empty boundary
amandaghassaei's avatar
amandaghassaei committed
227
            if (pos.x < 0.0 || pos.x >= u_textureSize.x || pos.y < 0.0 || pos.y >= u_textureSize.y) materialVal = vec2(0.0);
amandaghassaei's avatar
amandaghassaei committed
228
            else materialVal = bilinearInterp(pos, u_material, u_textureSize);
amandaghassaei's avatar
amandaghassaei committed
229

amandaghassaei's avatar
amandaghassaei committed
230
            gl_FragColor = vec4(materialVal, 0, 0);
amandaghassaei's avatar
setup  
amandaghassaei committed
231 232 233 234 235 236
        }
    </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>

amandaghassaei's avatar
amandaghassaei committed
237 238 239
    <script type="text/javascript" src="js/GLBoilerplate.js"></script>
    <script type="text/javascript" src="js/GPUMath.js"></script>
    <script type="text/javascript" src="js/main.js"></script>
amandaghassaei's avatar
setup  
amandaghassaei committed
240 241 242 243 244 245 246 247 248 249 250 251
</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/>
amandaghassaei's avatar
eod  
amandaghassaei committed
252
                I used the following sources to write this simulation:<br/><br/>
amandaghassaei's avatar
amandaghassaei committed
253 254
                <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/>
amandaghassaei's avatar
eod  
amandaghassaei committed
255
                <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/>
amandaghassaei's avatar
amandaghassaei committed
256
                <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/>
amandaghassaei's avatar
eod  
amandaghassaei committed
257 258
                <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>.
amandaghassaei's avatar
setup  
amandaghassaei committed
259 260 261 262 263 264 265 266
                <br/><br/>
            </div>
        </div>
    </div>
</div>

</body>
</html>