-
Notifications
You must be signed in to change notification settings - Fork 4
/
index.html
173 lines (134 loc) · 6.83 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Mass-Spring-Damper Shader</title>
<meta name="viewport" content="width=400">
<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 type="text/javascript" src="dependencies/jquery-3.1.0.min.js"></script>
<script type="text/javascript" src="dependencies/flat-ui.min.js"></script>
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-86531114-9', 'auto');
ga('send', 'pageview');
</script>
<script type="text/javascript" src="GlBoilerplate.js"></script>
<script type="text/javascript" src="main.js"></script>
<script id="2d-vertex-shader" type="x-shader/x-vertex">
attribute vec2 a_position;
uniform float u_flipY;
attribute vec2 a_texCoord;
varying vec2 v_texCoord;
void main() {
gl_Position = vec4(a_position.x, u_flipY*a_position.y, 0, 1);
v_texCoord = a_texCoord;
}
</script>
<script id="2d-fragment-shader" type="x-shader/x-fragment">
precision mediump float;
//texture arrays
//uniform sampler2D u_position;
uniform sampler2D u_image;//pos, velocity, acceleration = r, g, b
varying vec2 v_texCoord;
uniform vec2 u_textureSize;
uniform vec2 u_mouseCoord;
uniform float u_mouseEnable;
uniform float u_kSpring;
uniform float u_dSpring;
uniform float u_mass;
uniform float u_dt;
uniform float u_renderFlag;
void main() {
vec2 onePixel = vec2(1.0, 1.0)/u_textureSize;
vec4 currentState = texture2D(u_image, v_texCoord);
if (u_renderFlag == 1.0){
float position = currentState.r/20.0;
position += 0.5;
if (position > 1.0) position = 1.0;
if (position < 0.0) position = 0.0;
if (position < 0.5){
position *= 2.0;
//position = 0 -> blue
//position = 1 -> magenta
gl_FragColor = vec4((255.0*position)/255.0,(179.0*(1.0-position))/255.0,(150.0-54.0*position)/255.0,1.0);
} else {
position -= 0.5;
position *= 2.0;
//position = 0 -> magenta
//position = 1 -> white
gl_FragColor = vec4((255.0-(10.0*position))/255.0,(223.0*position)/255.0,(106.0+(67.0*position))/255.0,1.0);
}
return;
}
float fTotal = 0.0;
if (u_mouseEnable == 1.0){
vec2 pxDistFromMouse = (v_texCoord - u_mouseCoord)*(v_texCoord - u_mouseCoord)/onePixel;
float tol = 0.005;
if (pxDistFromMouse.x < tol && pxDistFromMouse.y < tol){
fTotal -= 20.0;//upward force from mouse
}
}
for (int i=-1;i<=1;i+=2){
for (int j=-1;j<=1;j+=2){
if (i == 0 && j == 0) continue;
vec2 neighborCoord = v_texCoord + vec2(onePixel.x*float(i), onePixel.y*float(j));
vec4 neighborState;
if (neighborCoord.x < 0.0 || neighborCoord.y < 0.0 || neighborCoord.x >= 1.0 || neighborCoord.y >= 1.0){
neighborState = vec4(0.0,0.0,0.0,1.0);
} else {
neighborState = texture2D(u_image, neighborCoord);
}
float deltaP = neighborState.r - currentState.r;
float deltaV = neighborState.g - currentState.g;
fTotal += u_kSpring*deltaP + u_dSpring*deltaV;
}
}
float acceleration = fTotal/u_mass;
float velocity = acceleration*u_dt + currentState.g;
float position = velocity*u_dt + currentState.r;
gl_FragColor = vec4(position,velocity,acceleration,1);
}
</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>Mass-Spring-Damper Shader</b><br/>
<img src="img.jpg" style="width:100%;margin-top:10px"><br/><br/>
This is a physics simulation of a mesh of masses attached to their four nearest neighbors with springs and dampers, all running in a GPU fragment shader with WebGL.
In the simulation, each pixel on the screen is a mass in a 2D mesh.
At each frame, the masses exert forces on each other and the resulting acceleration, velocity, and position of each mass is solved via
<a href="https://en.wikipedia.org/wiki/Euler_method" target="_blank">Euler integration</a>. The vertical displacement of the masses is indicated by the color
of the pixel, blue pixels have positive vertical displacement, white have negative displacement, and pink is zero displacement.
Scrolling over with your mouse applies an upward force to the nearby pixels.
The physics is equivalent to a <a href="https://en.wikipedia.org/wiki/Wave_equation" target="_blank">discrete, damped 2D wave equation</a>
or <a href="https://en.wikipedia.org/wiki/Cloth_modeling" target="_blank">cloth simulation</a>. Masses at the edges of the screen are fixed with zero displacement,
making the simulation behave like a giant trampoline.
<br/><br/>
By <a href="http://www.amandaghassaei.com/" target="_blank">Amanda Ghassaei</a>, code on <a href="https://github.com/amandaghassaei/MassSpringShader" target="_blank">Github</a>.
<br/><br/>
</div>
</div>
</div>
</div>
<div class="modal fade" id="noSupportModal" tabindex="-1" role="dialog" aria-labelledby="basicModal" aria-hidden="true">
<div class="modal-dialog modal-med">
<div class="modal-content">
<div class="modal-body">
This device/browser does not support some GPU functions needed by this app.
Please try again on desktop running Chrome/Firefox.<br/><br/>
</div>
</div>
</div>
</div>
</body>
</html>