@thi.ng/shader-ast-stdlib 0.12.21 → 0.12.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dev/boids.js DELETED
@@ -1,1433 +0,0 @@
1
- class Vector2 {
2
- constructor(x, y) {
3
- this.x = x;
4
- this.y = y;
5
- }
6
-
7
- static get zero() {
8
- return new Vector2(0.0, 0.0);
9
- }
10
-
11
- static add(v1, v2) {
12
- return new Vector2(v1.x + v2.x, v1.y + v2.y);
13
- }
14
-
15
- static sub(v1, v2) {
16
- return new Vector2(v1.x - v2.x, v1.y - v2.y);
17
- }
18
-
19
- static mul(v, s) {
20
- return new Vector2(v.x * s, v.y * s);
21
- }
22
-
23
- static div(v, s) {
24
- return new Vector2(v.x / s, v.y / s);
25
- }
26
-
27
- static norm(v) {
28
- const m = v.mag();
29
- return new Vector2(v.x / m, v.y / m);
30
- }
31
-
32
- static dot(v1, v2) {
33
- return v1.x * v2.x + v1.y * v2.y;
34
- }
35
-
36
- static dist(v1, v2) {
37
- const v = Vector2.sub(v1, v2);
38
- return v.mag();
39
- }
40
-
41
- add(v) {
42
- this.x += v.x;
43
- this.y += v.y;
44
- return this;
45
- }
46
-
47
- sub(v) {
48
- this.x -= v.x;
49
- this.y -= v.y;
50
- return this;
51
- }
52
-
53
- mul(s) {
54
- this.x *= s;
55
- this.y *= s;
56
- return this;
57
- }
58
-
59
- div(s) {
60
- this.x /= s;
61
- this.y /= s;
62
- return this;
63
- }
64
-
65
- ceil() {
66
- this.x = Math.ceil(this.x);
67
- this.y = Math.ceil(this.y);
68
- return this;
69
- }
70
-
71
- mag() {
72
- return Math.sqrt(this.sqMag());
73
- }
74
-
75
- sqMag() {
76
- return this.x * this.x + this.y * this.y;
77
- }
78
-
79
- norm() {
80
- return Vector2.norm(this);
81
- }
82
-
83
- dot(v) {
84
- return Vector3.dot(this, v);
85
- }
86
- }
87
-
88
- function createShader(gl, source, type) {
89
- const shader = gl.createShader(type);
90
- gl.shaderSource(shader, source);
91
- gl.compileShader(shader);
92
- if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
93
- throw new Error(gl.getShaderInfoLog(shader) + source);
94
- }
95
- return shader;
96
- }
97
-
98
- function createProgram(gl, vertexShader, fragmentShader) {
99
- const program = gl.createProgram();
100
- gl.attachShader(program, vertexShader);
101
- gl.attachShader(program, fragmentShader);
102
- gl.linkProgram(program);
103
- if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
104
- throw new Error(gl.getProgramInfoLog(program));
105
- }
106
- return program;
107
- }
108
-
109
- function createVbo(gl, array, usage) {
110
- const vbo = gl.createBuffer();
111
- gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
112
- gl.bufferData(
113
- gl.ARRAY_BUFFER,
114
- array,
115
- usage !== undefined ? usage : gl.STATIC_DRAW
116
- );
117
- gl.bindBuffer(gl.ARRAY_BUFFER, null);
118
- return vbo;
119
- }
120
-
121
- function createIbo(gl, array) {
122
- const ibo = gl.createBuffer();
123
- gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ibo);
124
- gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, array, gl.STATIC_DRAW);
125
- gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
126
- return ibo;
127
- }
128
-
129
- function createVao(gl, vboObjs, ibo) {
130
- const vao = gl.createVertexArray();
131
- gl.bindVertexArray(vao);
132
- if (ibo !== undefined) {
133
- gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ibo);
134
- }
135
- vboObjs.forEach((vboObj) => {
136
- gl.bindBuffer(gl.ARRAY_BUFFER, vboObj.buffer);
137
- gl.enableVertexAttribArray(vboObj.index);
138
- gl.vertexAttribPointer(
139
- vboObj.index,
140
- vboObj.size,
141
- gl.FLOAT,
142
- false,
143
- 0,
144
- 0
145
- );
146
- });
147
- gl.bindVertexArray(null);
148
- if (ibo !== undefined) {
149
- gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
150
- }
151
- gl.bindBuffer(gl.ARRAY_BUFFER, null);
152
- return vao;
153
- }
154
-
155
- function createTexture(gl, size, internalFormat, format, type) {
156
- const texture = gl.createTexture();
157
- gl.bindTexture(gl.TEXTURE_2D, texture);
158
- gl.texImage2D(
159
- gl.TEXTURE_2D,
160
- 0,
161
- internalFormat,
162
- size,
163
- size,
164
- 0,
165
- format,
166
- type,
167
- null
168
- );
169
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
170
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
171
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
172
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
173
- gl.bindTexture(gl.TEXTURE_2D, null);
174
- return texture;
175
- }
176
-
177
- function getUniformLocations(gl, program, keys) {
178
- const locations = {};
179
- keys.forEach((key) => {
180
- locations[key] = gl.getUniformLocation(program, key);
181
- });
182
- return locations;
183
- }
184
-
185
- function setTextureAsUniform(gl, index, texture, location) {
186
- gl.activeTexture(gl.TEXTURE0 + index);
187
- gl.bindTexture(gl.TEXTURE_2D, texture);
188
- gl.uniform1i(location, index);
189
- }
190
-
191
- (function() {
192
- const FILL_SCREEN_VERTEX_SHADER_SOURCE = `#version 300 es
193
-
194
- layout (location = 0) in vec2 position;
195
-
196
- void main(void) {
197
- gl_Position = vec4(position, 0.0, 1.0);
198
- }
199
- `;
200
-
201
- const INITIALIZE_BOID_FRAGMENT_SHADER_SOURCE = `#version 300 es
202
-
203
- precision highp float;
204
-
205
- layout (location = 0) out vec2 o_position;
206
- layout (location = 1) out vec2 o_velocity;
207
-
208
- uniform vec2 u_randomSeed;
209
- uniform uint u_boidNum;
210
- uniform uint u_boidTextureSize;
211
- uniform float u_maxSpeed;
212
- uniform vec2 u_simulationSpace;
213
-
214
- uint convertCoordToIndex(uvec2 coord, uint sizeX) {
215
- return coord.x + sizeX * coord.y;
216
- }
217
-
218
- float random(vec2 x){
219
- return fract(sin(dot(x,vec2(12.9898, 78.233))) * 43758.5453);
220
- }
221
-
222
- void main(void) {
223
- uint index = convertCoordToIndex(uvec2(gl_FragCoord.xy), u_boidTextureSize);
224
-
225
- if (index >= u_boidNum) { // unused pixels
226
- o_position = vec2(0.0);
227
- o_velocity = vec2(0.0);
228
- return;
229
- }
230
-
231
- o_position = vec2(
232
- random(gl_FragCoord.xy * 0.013 + random(u_randomSeed * vec2(32.19, 27.51) * 1000.0)),
233
- random(gl_FragCoord.xy * 0.029 + random(u_randomSeed * vec2(19.56, 11.34) * 1000.0))
234
- ) * (u_simulationSpace - 1e-5) + 1e-5 * 0.5;
235
- o_velocity = normalize(vec2(
236
- random(gl_FragCoord.xy * 0.059 + random(u_randomSeed * vec2(27.31, 16.91) * 1000.0)),
237
- random(gl_FragCoord.xy * 0.038 + random(u_randomSeed * vec2(25.95, 19.47) * 1000.0))
238
- ) * 2.0 - 1.0) * u_maxSpeed;
239
- }
240
- `;
241
-
242
- const UPDATE_BOID_FRAGMENT_SHADER_SOURCE = `#version 300 es
243
-
244
- precision highp float;
245
-
246
- layout (location = 0) out vec2 o_position;
247
- layout (location = 1) out vec2 o_velocity;
248
-
249
- uniform sampler2D u_positionTexture;
250
- uniform sampler2D u_velocityTexture;
251
- uniform sampler2D u_forceTexture;
252
- uniform float u_deltaTime;
253
- uniform float u_maxSpeed;
254
- uniform uint u_boidNum;
255
- uniform uint u_boidTextureSize;
256
- uniform vec2 u_simulationSpace;
257
-
258
- uint convertCoordToIndex(uvec2 coord, uint sizeX) {
259
- return coord.x + sizeX * coord.y;
260
- }
261
-
262
- vec2 limit(vec2 v, float max) {
263
- if (length(v) < max) {
264
- return normalize(v) * max;
265
- }
266
- return v;
267
- }
268
-
269
- void main(void) {
270
- ivec2 coord = ivec2(gl_FragCoord.xy);
271
-
272
- uint index = convertCoordToIndex(uvec2(coord), u_boidTextureSize);
273
- if (index >= u_boidNum) { // unused pixels
274
- o_position = vec2(0.0);
275
- o_velocity = vec2(0.0);
276
- return;
277
- }
278
-
279
- vec2 position = texelFetch(u_positionTexture, coord, 0).xy;
280
- vec2 velocity = texelFetch(u_velocityTexture, coord, 0).xy;
281
- vec2 force = texelFetch(u_forceTexture, coord, 0).xy;
282
-
283
- vec2 nextVelocity = limit(velocity + u_deltaTime * force, u_maxSpeed);
284
- vec2 nextPosition = position + u_deltaTime * velocity;
285
-
286
- if (nextPosition.x < 1e-6) {
287
- nextPosition.x = 1e-6;
288
- nextVelocity.x *= -1.0;
289
- }
290
- if (nextPosition.x > u_simulationSpace.x - 1e-6) {
291
- nextPosition.x = u_simulationSpace.x - 1e-6;
292
- nextVelocity.x *= -1.0;
293
- }
294
- if (nextPosition.y < 1e-6) {
295
- nextPosition.y = 1e-6;
296
- nextVelocity.y *= -1.0;
297
- }
298
- if (nextPosition.y > u_simulationSpace.y - 1e-6) {
299
- nextPosition.y = u_simulationSpace.y - 1e-6;
300
- nextVelocity.y *= -1.0;
301
- }
302
-
303
- o_position = nextPosition;
304
- o_velocity = nextVelocity;
305
- }
306
- `;
307
-
308
- const COMPUTE_FORCE_FRAGMENT_SHADER_SOURCE = `#version 300 es
309
-
310
- precision highp float;
311
- precision highp isampler2D;
312
- precision highp usampler2D;
313
-
314
- // 4294967295 = 2^32 - 1
315
- #define MAX_32UI 4294967295u
316
-
317
- out vec2 o_force;
318
-
319
- uniform sampler2D u_positionTexture;
320
- uniform sampler2D u_velocityTexture;
321
- uniform usampler2D u_bucketTexture;
322
- uniform usampler2D u_bucketReferrerTexture;
323
-
324
- uniform vec3 u_radius; // x: separation, y: alignment: z: cohesion
325
- uniform vec3 u_weight; // x: separation, y: alignment: z: cohesion
326
- uniform float u_maxSpeed;
327
- uniform float u_maxForce;
328
- uniform float u_boundaryIntensity;
329
- uniform uint u_boidNum;
330
- uniform float u_bucketSize;
331
- uniform ivec2 u_bucketNum;
332
- uniform vec2 u_simulationSpace;
333
-
334
- uint convertCoordToIndex(uvec2 coord, uint sizeX) {
335
- return coord.x + sizeX * coord.y;
336
- }
337
-
338
- uvec2 convertIndexToCoord(uint index, uint sizeX) {
339
- return uvec2(index % sizeX, index / sizeX);
340
- }
341
-
342
- vec2 limit(vec2 v, float max) {
343
- if (length(v) > max) {
344
- return normalize(v) * max;
345
- }
346
- return v;
347
- }
348
-
349
- void findNeighbors(vec2 position, ivec2 bucketPosition, ivec2 bucketNum, uint boidTextureSizeX, uint bucketReferrerTextureSizeX, inout vec2 separation, inout vec2 alignment, inout vec3 cohesion) {
350
- if (bucketPosition.x < 0 || bucketPosition.x >= bucketNum.x ||
351
- bucketPosition.y < 0 || bucketPosition.y >= bucketNum.y) {
352
- return;
353
- }
354
- uint bucketIndex = uint(bucketPosition.x + bucketNum.x * bucketPosition.y);
355
- ivec2 coord = ivec2(convertIndexToCoord(bucketIndex, bucketReferrerTextureSizeX));
356
-
357
- uvec2 bucketReferrer = texelFetch(u_bucketReferrerTexture, coord, 0).xy;
358
-
359
- if (bucketReferrer.x == MAX_32UI || bucketReferrer.y == MAX_32UI) {
360
- return;
361
- }
362
-
363
- for (uint i = bucketReferrer.x; i <= bucketReferrer.y; i++) {
364
- uint boidIndex = texelFetch(u_bucketTexture, ivec2(convertIndexToCoord(i, boidTextureSizeX)), 0).y;
365
-
366
- ivec2 boidCoord = ivec2(convertIndexToCoord(boidIndex, boidTextureSizeX));
367
- vec2 otherPos = texelFetch(u_positionTexture, boidCoord, 0).xy;
368
-
369
- float dist = length(position - otherPos);
370
-
371
- if (dist == 0.0) {
372
- continue;
373
- }
374
-
375
- if (dist < u_radius.x) {
376
- separation += normalize(position - otherPos) / dist;
377
- }
378
-
379
- if (dist < u_radius.y) {
380
- vec2 otherVel = texelFetch(u_velocityTexture, boidCoord, 0).xy;
381
- alignment += otherVel;
382
- }
383
-
384
- if (dist < u_radius.z) {
385
- cohesion.xy += otherPos;
386
- cohesion.z += 1.0;
387
- }
388
- }
389
- }
390
-
391
- vec2 computeForceFromBoids(vec2 position, vec2 velocity, uint boidTextureSizeX) {
392
- uint bucketReferrerTextureSizeX = uint(textureSize(u_bucketReferrerTexture, 0).x);
393
-
394
- vec2 bucketPosition = position / u_bucketSize;
395
- int xOffset = fract(bucketPosition.x) < 0.5 ? -1 : 1;
396
- int yOffset = fract(bucketPosition.y) < 0.5 ? -1 : 1;
397
-
398
- ivec2 bucketPosition00 = ivec2(bucketPosition);
399
- ivec2 bucketPosition10 = bucketPosition00 + ivec2(xOffset, 0);
400
- ivec2 bucketPosition01 = bucketPosition00 + ivec2(0, yOffset);
401
- ivec2 bucketPosition11 = bucketPosition00 + ivec2(xOffset, yOffset);
402
-
403
- vec2 separation = vec2(0.0);
404
- vec2 alignment = vec2(0.0);
405
- vec3 cohesion = vec3(0.0);
406
- findNeighbors(position, bucketPosition00, u_bucketNum, boidTextureSizeX, bucketReferrerTextureSizeX, separation, alignment, cohesion);
407
- findNeighbors(position, bucketPosition10, u_bucketNum, boidTextureSizeX, bucketReferrerTextureSizeX, separation, alignment, cohesion);
408
- findNeighbors(position, bucketPosition01, u_bucketNum, boidTextureSizeX, bucketReferrerTextureSizeX, separation, alignment, cohesion);
409
- findNeighbors(position, bucketPosition11, u_bucketNum, boidTextureSizeX, bucketReferrerTextureSizeX, separation, alignment, cohesion);
410
-
411
- vec2 separationForce = vec2(0.0);
412
- if (separation.xy != vec2(0.0)) {
413
- vec2 desiredVelocity = normalize(separation.xy) * u_maxSpeed;
414
- separationForce = limit(desiredVelocity - velocity, u_maxForce);
415
- }
416
-
417
- vec2 alignmentForce = vec2(0.0);
418
- if (alignment.xy != vec2(0.0)) {
419
- vec2 desiredVelocity = normalize(alignment.xy) * u_maxSpeed;
420
- alignmentForce = limit(desiredVelocity - velocity, u_maxForce);
421
- }
422
-
423
- vec2 cohesionForce = vec2(0.0);
424
- if (cohesion.z != 0.0) {
425
- vec2 target = cohesion.xy / cohesion.z;
426
- vec2 desiredVelocity = normalize(target - position) * u_maxSpeed;
427
- cohesionForce = limit(desiredVelocity - velocity, u_maxForce);
428
- }
429
-
430
- separationForce *= u_weight.x;
431
- alignmentForce *= u_weight.y;
432
- cohesionForce *= u_weight.z;
433
-
434
- return separationForce + alignmentForce + cohesionForce;
435
- }
436
-
437
- vec2 computeForceFromWalls(vec2 position) {
438
- vec2 force = vec2(0.0);
439
- if (position.x < u_radius.x) {
440
- force += vec2(u_boundaryIntensity, 0.0) / position.x;
441
- }
442
- if (u_simulationSpace.x - position.x < u_radius.x) {
443
- force += vec2(-u_boundaryIntensity, 0.0) / (u_simulationSpace.x - position.x);
444
- }
445
- if (position.y < u_radius.x) {
446
- force += vec2(0.0, u_boundaryIntensity) / position.y;
447
- }
448
- if (u_simulationSpace.y - position.y < u_radius.x) {
449
- force += vec2(0.0, -u_boundaryIntensity) / (u_simulationSpace.y - position.y);
450
- }
451
- return force;
452
- }
453
-
454
- vec2 computeForce(uint boidTextureSizeX) {
455
-
456
- ivec2 coord = ivec2(gl_FragCoord.xy);
457
- vec2 position = texelFetch(u_positionTexture, coord, 0).xy;
458
- vec2 velocity = texelFetch(u_velocityTexture, coord, 0).xy;
459
-
460
- vec2 forceFromBoids = computeForceFromBoids(position, velocity, boidTextureSizeX);
461
- vec2 forceFromWalls = computeForceFromWalls(position);
462
-
463
- return limit(forceFromBoids + forceFromWalls, u_maxForce);
464
- }
465
-
466
- void main(void) {
467
- uint boidTextureSizeX = uint(textureSize(u_positionTexture, 0).x);
468
- uint index = convertCoordToIndex(uvec2(gl_FragCoord.xy), boidTextureSizeX);
469
- if (index >= u_boidNum) { // unused pixels
470
- o_force = vec2(0.0);
471
- return;
472
- }
473
- o_force = computeForce(boidTextureSizeX);
474
- }
475
- `;
476
-
477
- const RENDER_BOID_VERTEX_SHADER_SOURCE = `#version 300 es
478
-
479
- precision highp isampler2D;
480
- precision highp usampler2D;
481
-
482
- const float PI = 3.14159265359;
483
-
484
- out float v_angle;
485
-
486
- uniform sampler2D u_positionTexture;
487
- uniform sampler2D u_velocityTexture;
488
- uniform vec2 u_canvasSize;
489
- uniform vec2 u_simulationSpace;
490
- uniform float u_boidSize;
491
-
492
- ivec2 convertIndexToCoord(int index, int sizeX) {
493
- return ivec2(index % sizeX, index / sizeX);
494
- }
495
-
496
- void main(void) {
497
- ivec2 coord = convertIndexToCoord(gl_VertexID, textureSize(u_positionTexture, 0).x);
498
- vec2 position = texelFetch(u_positionTexture, coord, 0).xy;
499
- vec2 scale = min(u_canvasSize.x, u_canvasSize.y) / u_canvasSize;
500
- float minSimulationSpace = min(u_simulationSpace.x, u_simulationSpace.y);
501
- vec2 canvasPos = scale * ((position / minSimulationSpace) * 2.0 - u_simulationSpace / minSimulationSpace);
502
- gl_Position = vec4(canvasPos, 0.0, 1.0);
503
- gl_PointSize = u_boidSize;
504
-
505
- vec2 velocity = texelFetch(u_velocityTexture, coord, 0).xy;
506
- if (velocity.x == 0.0) {
507
- v_angle = 0.25 * PI;
508
- } else {
509
- v_angle = atan(velocity.y, velocity.x);
510
- }
511
- }
512
- `;
513
-
514
- const RENDER_BOID_FRAGMENT_SHADER_SOURCE = `#version 300 es
515
-
516
- precision highp float;
517
-
518
- in float v_angle;
519
-
520
- out vec4 o_color;
521
-
522
- mat2 rotate(float r) {
523
- float c = cos(r);
524
- float s = sin(r);
525
- return mat2(c, s, -s, c);
526
- }
527
-
528
- float sdTriangleIsosceles(vec2 p, vec2 q) {
529
- p.x = abs(p.x);
530
- vec2 a = p - q * clamp(dot(p, q) / dot(q, q), 0.0, 1.0);
531
- vec2 b = p - q * vec2(clamp(p.x / q.x, 0.0, 1.0), 1.0);
532
- float s = -sign(q.y);
533
- vec2 d = min(vec2(dot(a, a), s * (p.x * q.y - p.y * q.x)), vec2(dot(b, b), s * (p.y - q.y)));
534
- return -sqrt(d.x) * sign(d.y);
535
- }
536
-
537
- void main(void) {
538
- vec2 p = ((gl_PointCoord - 0.5) * 2.0).yx;
539
- p *= rotate(v_angle);
540
- p.y *= -1.0;
541
- if (sdTriangleIsosceles(p * 1.25, vec2(1.0, 5.0)) <= 0.0) {
542
- o_color = vec4(vec3(0.8), 1.0);
543
- } else {
544
- discard;
545
- }
546
- }
547
- `;
548
-
549
- const INITIALIZE_BUCKET_FRAGMENT_SHADER_SOURCE = `#version 300 es
550
-
551
- precision highp float;
552
-
553
- // 4294967295 = 2^32 - 1
554
- #define MAX_32UI 4294967295u
555
-
556
- out uvec2 o_bucket;
557
-
558
- uniform sampler2D u_positionTexture;
559
- uniform float u_bucketSize;
560
- uniform uint u_boidNum;
561
- uniform uvec2 u_bucketNum;
562
-
563
- uint convertCoordToIndex(uvec2 coord, uint sizeX) {
564
- return coord.x + sizeX * coord.y;
565
- }
566
-
567
- uint getBucketIndex(vec2 position) {
568
- uvec2 bucketCoord = uvec2(position / u_bucketSize);
569
- return bucketCoord.x + bucketCoord.y * u_bucketNum.x;
570
- }
571
-
572
- void main(void) {
573
- uint positionTextureSizeX = uint(textureSize(u_positionTexture, 0).x);
574
- uint boidIndex = convertCoordToIndex(uvec2(gl_FragCoord.xy), positionTextureSizeX);
575
- if (boidIndex >= u_boidNum) {
576
- o_bucket = uvec2(MAX_32UI, 0); // = uvec2(2^32 - 1, 0)
577
- }
578
- vec2 position = texelFetch(u_positionTexture, ivec2(gl_FragCoord.xy), 0).xy;
579
- uint bucketIndex = getBucketIndex(position);
580
- o_bucket = uvec2(bucketIndex, boidIndex);
581
- }
582
- `;
583
-
584
- const SWAP_BUCKET_INDEX_FRAGMENT_SHADER_SOURCE = `#version 300 es
585
-
586
- precision highp float;
587
- precision highp usampler2D;
588
-
589
- out uvec2 o_bucket;
590
-
591
- uniform usampler2D u_bucketTexture;
592
- uniform uint u_size;
593
- uniform uint u_blockStep;
594
- uniform uint u_subBlockStep;
595
-
596
- uint convertCoordToIndex(uvec2 coord, uint sizeX) {
597
- return coord.x + sizeX * coord.y;
598
- }
599
-
600
- uvec2 convertIndexToCoord(uint index, uint sizeX) {
601
- return uvec2(index % sizeX, index / sizeX);
602
- }
603
-
604
- void main(void) {
605
- uint index = convertCoordToIndex(uvec2(gl_FragCoord.xy), u_size);
606
- uint d = 1u << (u_blockStep - u_subBlockStep);
607
-
608
- bool up = ((index >> u_blockStep) & 2u) == 0u;
609
-
610
- uint targetIndex;
611
- bool first = (index & d) == 0u;
612
- if (first) {
613
- targetIndex = index | d;
614
- } else {
615
- targetIndex = index & ~d;
616
- up = !up;
617
- }
618
-
619
- uvec2 a = texelFetch(u_bucketTexture, ivec2(gl_FragCoord.xy), 0).xy;
620
- uvec2 b = texelFetch(u_bucketTexture, ivec2(convertIndexToCoord(targetIndex, u_size)), 0).xy;
621
-
622
- if (a.x == b.x || (a.x >= b.x) == up) {
623
- o_bucket = b;
624
- } else {
625
- o_bucket = a;
626
- }
627
- }
628
-
629
- `;
630
-
631
- const INITIALIZE_BUCKET_REFERRER_FRAGMENT_SHADER_SOURCE = `#version 300 es
632
-
633
- precision highp float;
634
- precision highp usampler2D;
635
-
636
- // 4294967295 = 2^32 - 1
637
- #define MAX_32UI 4294967295u
638
-
639
- out uvec2 o_referrer;
640
-
641
- uniform uvec2 u_bucketReferrerTextureSize;
642
- uniform usampler2D u_bucketTexture;
643
- uniform uint u_boidNumN;
644
- uniform uvec2 u_bucketNum;
645
-
646
- uint convertCoordToIndex(uvec2 coord, uint sizeX) {
647
- return coord.x + sizeX * coord.y;
648
- }
649
-
650
- uvec2 convertIndexToCoord(uint index, uint sizeX) {
651
- return uvec2(index % sizeX, index / sizeX);
652
- }
653
-
654
- uint getBucketIndex(uint particleIndex, uint particleTextureSizeX) {
655
- return texelFetch(u_bucketTexture, ivec2(convertIndexToCoord(particleIndex, particleTextureSizeX)), 0).x;
656
- }
657
-
658
-
659
- uint binarySearchMinIndex(uint target, uint from, uint to, uint particleTextureSizeX) {
660
- for (uint i = 0u; i < u_boidNumN + 1u; i++) {
661
- uint middle = from + (to - from) / 2u;
662
- uint bucketIndex = getBucketIndex(middle, particleTextureSizeX);
663
- if (bucketIndex < target) {
664
- from = middle + 1u;
665
- } else {
666
- to = middle;
667
- }
668
- if (from == to) {
669
- if (getBucketIndex(from, particleTextureSizeX) == target) {
670
- return from;
671
- } else {
672
- return MAX_32UI;
673
- }
674
- }
675
- }
676
- return MAX_32UI;
677
- }
678
-
679
- uint binarySearchMaxIndex(uint target, uint from, uint to, uint particleTextureSizeX) {
680
- for (uint i = 0u; i < u_boidNumN + 1u; i++) {
681
- uint middle = from + (to - from) / 2u + 1u;
682
- uint bucketIndex = getBucketIndex(middle, particleTextureSizeX);
683
- if (bucketIndex > target) {
684
- to = middle - 1u;
685
- } else {
686
- from = middle;
687
- }
688
- if (from == to) {
689
- if (getBucketIndex(from, particleTextureSizeX) == target) {
690
- return from;
691
- } else {
692
- return MAX_32UI;
693
- }
694
- }
695
- }
696
- return MAX_32UI;
697
- }
698
-
699
- uvec2 binarySearchRange(uint target, uint from, uint to) {
700
- uint boidTextureSizeX = uint(textureSize(u_bucketTexture, 0).x);
701
- from = binarySearchMinIndex(target, from, to, boidTextureSizeX);
702
- to = from == MAX_32UI ? MAX_32UI : binarySearchMaxIndex(target, from, to, boidTextureSizeX);
703
- return uvec2(from, to);
704
- }
705
-
706
- void main(void) {
707
- uint bucketIndex = convertCoordToIndex(uvec2(gl_FragCoord.xy), u_bucketReferrerTextureSize.x);
708
- uint maxBucketIndex = u_bucketNum.x * u_bucketNum.y;
709
-
710
- if (bucketIndex >= maxBucketIndex) {
711
- o_referrer = uvec2(MAX_32UI, MAX_32UI);
712
- return;
713
- }
714
-
715
- uvec2 boidTextureSize = uvec2(textureSize(u_bucketTexture, 0));
716
- uint boidNum = boidTextureSize.x * boidTextureSize.y;
717
-
718
- o_referrer = binarySearchRange(bucketIndex, 0u, boidNum - 1u);
719
- }
720
- `;
721
-
722
- const VERTICES_POSITION = new Float32Array([
723
- -1.0,
724
- -1.0,
725
- 1.0,
726
- -1.0,
727
- -1.0,
728
- 1.0,
729
- 1.0,
730
- 1.0
731
- ]);
732
-
733
- const VERTICES_INDEX = new Int16Array([0, 1, 2, 3, 2, 1]);
734
-
735
- function createInitializeBoidProgram(gl) {
736
- const vertexShader = createShader(
737
- gl,
738
- FILL_SCREEN_VERTEX_SHADER_SOURCE,
739
- gl.VERTEX_SHADER
740
- );
741
- const fragmentShader = createShader(
742
- gl,
743
- INITIALIZE_BOID_FRAGMENT_SHADER_SOURCE,
744
- gl.FRAGMENT_SHADER
745
- );
746
- return createProgram(gl, vertexShader, fragmentShader);
747
- }
748
-
749
- function createUpdateBoidProgram(gl) {
750
- const vertexShader = createShader(
751
- gl,
752
- FILL_SCREEN_VERTEX_SHADER_SOURCE,
753
- gl.VERTEX_SHADER
754
- );
755
- const fragmentShader = createShader(
756
- gl,
757
- UPDATE_BOID_FRAGMENT_SHADER_SOURCE,
758
- gl.FRAGMENT_SHADER
759
- );
760
- return createProgram(gl, vertexShader, fragmentShader);
761
- }
762
-
763
- function createComputeForceProgram(gl) {
764
- const vertexShader = createShader(
765
- gl,
766
- FILL_SCREEN_VERTEX_SHADER_SOURCE,
767
- gl.VERTEX_SHADER
768
- );
769
- const fragmentShader = createShader(
770
- gl,
771
- COMPUTE_FORCE_FRAGMENT_SHADER_SOURCE,
772
- gl.FRAGMENT_SHADER
773
- );
774
- return createProgram(gl, vertexShader, fragmentShader);
775
- }
776
-
777
- function createRenderBoidProgram(gl) {
778
- const vertexShader = createShader(
779
- gl,
780
- RENDER_BOID_VERTEX_SHADER_SOURCE,
781
- gl.VERTEX_SHADER
782
- );
783
- const fragmentShader = createShader(
784
- gl,
785
- RENDER_BOID_FRAGMENT_SHADER_SOURCE,
786
- gl.FRAGMENT_SHADER
787
- );
788
- return createProgram(gl, vertexShader, fragmentShader);
789
- }
790
-
791
- function createInitializeBucketProgram(gl) {
792
- const vertexShader = createShader(
793
- gl,
794
- FILL_SCREEN_VERTEX_SHADER_SOURCE,
795
- gl.VERTEX_SHADER
796
- );
797
- const fragmentShader = createShader(
798
- gl,
799
- INITIALIZE_BUCKET_FRAGMENT_SHADER_SOURCE,
800
- gl.FRAGMENT_SHADER
801
- );
802
- return createProgram(gl, vertexShader, fragmentShader);
803
- }
804
-
805
- function createSwapBucketIndexProgram(gl) {
806
- const vertexShader = createShader(
807
- gl,
808
- FILL_SCREEN_VERTEX_SHADER_SOURCE,
809
- gl.VERTEX_SHADER
810
- );
811
- const fragmentShader = createShader(
812
- gl,
813
- SWAP_BUCKET_INDEX_FRAGMENT_SHADER_SOURCE,
814
- gl.FRAGMENT_SHADER
815
- );
816
- return createProgram(gl, vertexShader, fragmentShader);
817
- }
818
-
819
- function createInitializeBucketReferrerProgram(gl) {
820
- const vertexShader = createShader(
821
- gl,
822
- FILL_SCREEN_VERTEX_SHADER_SOURCE,
823
- gl.VERTEX_SHADER
824
- );
825
- const fragmentShader = createShader(
826
- gl,
827
- INITIALIZE_BUCKET_REFERRER_FRAGMENT_SHADER_SOURCE,
828
- gl.FRAGMENT_SHADER
829
- );
830
- return createProgram(gl, vertexShader, fragmentShader);
831
- }
832
-
833
- function createBoidFramebuffer(gl, size) {
834
- const framebuffer = gl.createFramebuffer();
835
- gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
836
- const positionTexture = createTexture(
837
- gl,
838
- size,
839
- gl.RG32F,
840
- gl.RG,
841
- gl.FLOAT
842
- );
843
- gl.bindTexture(gl.TEXTURE_2D, positionTexture);
844
- gl.framebufferTexture2D(
845
- gl.FRAMEBUFFER,
846
- gl.COLOR_ATTACHMENT0,
847
- gl.TEXTURE_2D,
848
- positionTexture,
849
- 0
850
- );
851
- const velocityTexture = createTexture(
852
- gl,
853
- size,
854
- gl.RG32F,
855
- gl.RG,
856
- gl.FLOAT
857
- );
858
- gl.bindTexture(gl.TEXTURE_2D, velocityTexture);
859
- gl.framebufferTexture2D(
860
- gl.FRAMEBUFFER,
861
- gl.COLOR_ATTACHMENT1,
862
- gl.TEXTURE_2D,
863
- velocityTexture,
864
- 0
865
- );
866
- gl.drawBuffers([gl.COLOR_ATTACHMENT0, gl.COLOR_ATTACHMENT1]);
867
- gl.bindFramebuffer(gl.FRAMEBUFFER, null);
868
- gl.bindTexture(gl.TEXTURE_2D, null);
869
- return {
870
- framebuffer: framebuffer,
871
- positionTexture: positionTexture,
872
- velocityTexture: velocityTexture
873
- };
874
- }
875
-
876
- function createForceFramebuffer(gl, size) {
877
- const framebuffer = gl.createFramebuffer();
878
- gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
879
- const forceTexture = createTexture(gl, size, gl.RG32F, gl.RG, gl.FLOAT);
880
- gl.bindTexture(gl.TEXTURE_2D, forceTexture);
881
- gl.framebufferTexture2D(
882
- gl.FRAMEBUFFER,
883
- gl.COLOR_ATTACHMENT0,
884
- gl.TEXTURE_2D,
885
- forceTexture,
886
- 0
887
- );
888
- gl.bindFramebuffer(gl.FRAMEBUFFER, null);
889
- gl.bindTexture(gl.TEXTURE_2D, null);
890
- return {
891
- framebuffer: framebuffer,
892
- forceTexture: forceTexture
893
- };
894
- }
895
-
896
- function createBucketFramebuffer(gl, size) {
897
- const framebuffer = gl.createFramebuffer();
898
- gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
899
- const bucketTexture = createTexture(
900
- gl,
901
- size,
902
- gl.RG32UI,
903
- gl.RG_INTEGER,
904
- gl.UNSIGNED_INT
905
- );
906
- gl.bindTexture(gl.TEXTURE_2D, bucketTexture);
907
- gl.framebufferTexture2D(
908
- gl.FRAMEBUFFER,
909
- gl.COLOR_ATTACHMENT0,
910
- gl.TEXTURE_2D,
911
- bucketTexture,
912
- 0
913
- );
914
- gl.bindFramebuffer(gl.FRAMEBUFFER, null);
915
- gl.bindTexture(gl.TEXTURE_2D, null);
916
- return {
917
- framebuffer: framebuffer,
918
- bucketTexture: bucketTexture
919
- };
920
- }
921
-
922
- function createBucketReferrerFramebuffer(gl, size) {
923
- const framebuffer = gl.createFramebuffer();
924
- gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
925
- const bucketReferrerTexture = createTexture(
926
- gl,
927
- size,
928
- gl.RG32UI,
929
- gl.RG_INTEGER,
930
- gl.UNSIGNED_INT
931
- );
932
- gl.bindTexture(gl.TEXTURE_2D, bucketReferrerTexture);
933
- gl.framebufferTexture2D(
934
- gl.FRAMEBUFFER,
935
- gl.COLOR_ATTACHMENT0,
936
- gl.TEXTURE_2D,
937
- bucketReferrerTexture,
938
- 0
939
- );
940
- gl.bindFramebuffer(gl.FRAMEBUFFER, null);
941
- gl.bindTexture(gl.TEXTURE_2D, null);
942
- return {
943
- framebuffer: framebuffer,
944
- bucketReferrerTexture: bucketReferrerTexture
945
- };
946
- }
947
-
948
- const canvas = document.getElementById("canvas");
949
- const resizeCanvas = function() {
950
- canvas.width = window.innerWidth;
951
- canvas.height = window.innerHeight;
952
- };
953
- window.addEventListener("resize", resizeCanvas);
954
- resizeCanvas();
955
-
956
- const gl = canvas.getContext("webgl2");
957
- gl.getExtension("EXT_color_buffer_float");
958
-
959
- const initializeBoidProgram = createInitializeBoidProgram(gl);
960
- const updateBoidProgram = createUpdateBoidProgram(gl);
961
- const computeForceProgram = createComputeForceProgram(gl);
962
- const renderBoidProgram = createRenderBoidProgram(gl);
963
- const initializeBucketProgram = createInitializeBucketProgram(gl);
964
- const swapBucketIndexProgram = createSwapBucketIndexProgram(gl);
965
- const initializeBucketReferrerProgram = createInitializeBucketReferrerProgram(
966
- gl
967
- );
968
-
969
- const initializeBoidUniforms = getUniformLocations(
970
- gl,
971
- initializeBoidProgram,
972
- [
973
- "u_randomSeed",
974
- "u_boidNum",
975
- "u_boidTextureSize",
976
- "u_maxSpeed",
977
- "u_simulationSpace"
978
- ]
979
- );
980
- const updateBoidUniforms = getUniformLocations(gl, updateBoidProgram, [
981
- "u_positionTexture",
982
- "u_velocityTexture",
983
- "u_forceTexture",
984
- "u_deltaTime",
985
- "u_boidNum",
986
- "u_boidTextureSize",
987
- "u_maxSpeed",
988
- "u_simulationSpace"
989
- ]);
990
- const computeForceUniforms = getUniformLocations(gl, computeForceProgram, [
991
- "u_positionTexture",
992
- "u_velocityTexture",
993
- "u_bucketTexture",
994
- "u_bucketReferrerTexture",
995
- "u_boidNum",
996
- "u_radius",
997
- "u_weight",
998
- "u_maxSpeed",
999
- "u_maxForce",
1000
- "u_boundaryIntensity",
1001
- "u_bucketSize",
1002
- "u_bucketNum",
1003
- "u_simulationSpace"
1004
- ]);
1005
- const renderBoidUniforms = getUniformLocations(gl, renderBoidProgram, [
1006
- "u_positionTexture",
1007
- "u_velocityTexture",
1008
- "u_canvasSize",
1009
- "u_simulationSpace",
1010
- "u_boidSize"
1011
- ]);
1012
- const initializeBucketUniforms = getUniformLocations(
1013
- gl,
1014
- initializeBucketProgram,
1015
- ["u_positionTexture", "u_bucketSize", "u_boidNum", "u_bucketNum"]
1016
- );
1017
- const swapBucketIndexUniforms = getUniformLocations(
1018
- gl,
1019
- swapBucketIndexProgram,
1020
- ["u_bucketTexture", "u_size", "u_blockStep", "u_subBlockStep"]
1021
- );
1022
- const initializeBucketReferrerUniforms = getUniformLocations(
1023
- gl,
1024
- initializeBucketReferrerProgram,
1025
- [
1026
- "u_bucketTexture",
1027
- "u_bucketReferrerTextureSize",
1028
- "u_boidNumN",
1029
- "u_bucketNum"
1030
- ]
1031
- );
1032
-
1033
- const fillScreenVao = createVao(
1034
- gl,
1035
- [{ buffer: createVbo(gl, VERTICES_POSITION), size: 2, index: 0 }],
1036
- createIbo(gl, VERTICES_INDEX)
1037
- );
1038
-
1039
- const MAX_BOID_NUM = 4294967295; // = 2^32 - 1
1040
- const MAX_BUCKET_NUM = 4294967295; // = 2^32 - 1
1041
-
1042
- const parameters = {
1043
- dynamic: {
1044
- "separation weight": 1.5,
1045
- "alignment weight": 1.0,
1046
- "cohesion weight": 1.0,
1047
- "max speed": 0.05,
1048
- "max force": 0.1,
1049
- "boundary intensity": 10.0,
1050
- "boid size": 12.0
1051
- },
1052
- static: {
1053
- "boid num": 8192,
1054
- "separation radius": 0.02,
1055
- "alignment radius": 0.04,
1056
- "cohesion radius": 0.03
1057
- },
1058
- reset: () => reset()
1059
- };
1060
-
1061
- let requestId = null;
1062
- function reset() {
1063
- if (requestId !== null) {
1064
- cancelAnimationFrame(requestId);
1065
- }
1066
-
1067
- const boidNum = parameters.static["boid num"];
1068
- if (boidNum > MAX_BOID_NUM) {
1069
- throw new Error(
1070
- `number of boids must be less than ${MAX_BOID_NUM}. current value is ${boidNum}.`
1071
- );
1072
- }
1073
- let boidTextureSize;
1074
- let boidNumN;
1075
- for (let i = 0; ; i++) {
1076
- boidTextureSize = 2 ** i;
1077
- if (boidTextureSize * boidTextureSize > boidNum) {
1078
- boidNumN = i * 2;
1079
- break;
1080
- }
1081
- }
1082
-
1083
- const separationRadius = parameters.static["separation radius"];
1084
- const alignmentRadius = parameters.static["alignment radius"];
1085
- const cohesionRadius = parameters.static["cohesion radius"];
1086
- const neighborRadius = Math.max(
1087
- separationRadius,
1088
- alignmentRadius,
1089
- cohesionRadius
1090
- );
1091
- const bucketSize = 2.0 * neighborRadius;
1092
- const simulationSpace = new Vector2(1.6, 1.2);
1093
- const bucketNum = Vector2.div(simulationSpace, bucketSize)
1094
- .ceil()
1095
- .add(new Vector2(1, 1));
1096
- const totalBuckets = bucketNum.x * bucketNum.y;
1097
- if (totalBuckets > MAX_BUCKET_NUM) {
1098
- throw new Error(
1099
- `number of buckets must be less than ${MAX_BUCKET_NUM}. current value is ${totalBuckets}.`
1100
- );
1101
- }
1102
- let bucketReferrerTextureSize;
1103
- for (let i = 0; ; i++) {
1104
- bucketReferrerTextureSize = 2 ** i;
1105
- if (
1106
- bucketReferrerTextureSize * bucketReferrerTextureSize >
1107
- totalBuckets
1108
- ) {
1109
- break;
1110
- }
1111
- }
1112
-
1113
- let boidFbObjR = createBoidFramebuffer(gl, boidTextureSize);
1114
- let boidFbObjW = createBoidFramebuffer(gl, boidTextureSize);
1115
- const swapBoidFbObj = function() {
1116
- const tmp = boidFbObjR;
1117
- boidFbObjR = boidFbObjW;
1118
- boidFbObjW = tmp;
1119
- };
1120
- let forceFbObj = createForceFramebuffer(gl, boidTextureSize);
1121
- let bucketFbObjR = createBucketFramebuffer(gl, boidTextureSize);
1122
- let bucketFbObjW = createBucketFramebuffer(gl, boidTextureSize);
1123
- const swapBucketFbObj = function() {
1124
- const tmp = bucketFbObjR;
1125
- bucketFbObjR = bucketFbObjW;
1126
- bucketFbObjW = tmp;
1127
- };
1128
- const bucketReferrerFbObj = createBucketReferrerFramebuffer(
1129
- gl,
1130
- bucketReferrerTextureSize
1131
- );
1132
-
1133
- const initializeBoids = function() {
1134
- gl.bindFramebuffer(gl.FRAMEBUFFER, boidFbObjW.framebuffer);
1135
- gl.viewport(0.0, 0.0, boidTextureSize, boidTextureSize);
1136
- gl.useProgram(initializeBoidProgram);
1137
- gl.uniform2f(
1138
- initializeBoidUniforms["u_randomSeed"],
1139
- Math.random() * 1000.0,
1140
- Math.random() * 1000.0
1141
- );
1142
- gl.uniform1ui(initializeBoidUniforms["u_boidNum"], boidNum);
1143
- gl.uniform1ui(
1144
- initializeBoidUniforms["u_boidTextureSize"],
1145
- boidTextureSize
1146
- );
1147
- gl.uniform1f(
1148
- initializeBoidUniforms["u_maxSpeed"],
1149
- parameters.dynamic["max speed"]
1150
- );
1151
- gl.uniform2f(
1152
- initializeBoidUniforms["u_simulationSpace"],
1153
- simulationSpace.x,
1154
- simulationSpace.y
1155
- );
1156
- gl.bindVertexArray(fillScreenVao);
1157
- gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);
1158
- gl.bindVertexArray(null);
1159
-
1160
- gl.bindFramebuffer(gl.FRAMEBUFFER, null);
1161
- swapBoidFbObj();
1162
- };
1163
-
1164
- const initializeBucket = function() {
1165
- gl.bindFramebuffer(gl.FRAMEBUFFER, bucketFbObjW.framebuffer);
1166
- gl.viewport(0.0, 0.0, boidTextureSize, boidTextureSize);
1167
- gl.useProgram(initializeBucketProgram);
1168
- setTextureAsUniform(
1169
- gl,
1170
- 0,
1171
- boidFbObjR.positionTexture,
1172
- initializeBucketUniforms["u_positionTexture"]
1173
- );
1174
- gl.uniform1f(initializeBucketUniforms["u_bucketSize"], bucketSize);
1175
- gl.uniform1ui(initializeBucketUniforms["u_boidNum"], boidNum);
1176
- gl.uniform2ui(
1177
- initializeBucketUniforms["u_bucketNum"],
1178
- bucketNum.x,
1179
- bucketNum.y
1180
- );
1181
- gl.bindVertexArray(fillScreenVao);
1182
- gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);
1183
- gl.bindVertexArray(null);
1184
- gl.bindFramebuffer(gl.FRAMEBUFFER, null);
1185
- swapBucketFbObj();
1186
- };
1187
-
1188
- const swapBucketIndex = function(i, j) {
1189
- gl.bindFramebuffer(gl.FRAMEBUFFER, bucketFbObjW.framebuffer);
1190
- gl.viewport(0.0, 0.0, boidTextureSize, boidTextureSize);
1191
- gl.useProgram(swapBucketIndexProgram);
1192
- setTextureAsUniform(
1193
- gl,
1194
- 0,
1195
- bucketFbObjR.bucketTexture,
1196
- swapBucketIndexUniforms["u_bucketTexture"]
1197
- );
1198
- gl.uniform1ui(
1199
- swapBucketIndexUniforms["u_size"],
1200
- boidTextureSize,
1201
- boidTextureSize
1202
- );
1203
- gl.uniform1ui(swapBucketIndexUniforms["u_blockStep"], i);
1204
- gl.uniform1ui(swapBucketIndexUniforms["u_subBlockStep"], j);
1205
- gl.bindVertexArray(fillScreenVao);
1206
- gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);
1207
- gl.bindVertexArray(null);
1208
- gl.bindFramebuffer(gl.FRAMEBUFFER, null);
1209
- swapBucketFbObj();
1210
- };
1211
-
1212
- const initializeBucketRefrrer = function() {
1213
- gl.bindFramebuffer(gl.FRAMEBUFFER, bucketReferrerFbObj.framebuffer);
1214
- gl.viewport(
1215
- 0.0,
1216
- 0.0,
1217
- bucketReferrerTextureSize,
1218
- bucketReferrerTextureSize
1219
- );
1220
- gl.useProgram(initializeBucketReferrerProgram);
1221
- setTextureAsUniform(
1222
- gl,
1223
- 0,
1224
- bucketFbObjR.bucketTexture,
1225
- initializeBucketReferrerUniforms["u_bucketTexture"]
1226
- );
1227
- gl.uniform1ui(
1228
- initializeBucketReferrerUniforms["u_boidNumN"],
1229
- boidNumN
1230
- );
1231
- gl.uniform2ui(
1232
- initializeBucketReferrerUniforms["u_bucketReferrerTextureSize"],
1233
- bucketReferrerTextureSize,
1234
- bucketReferrerTextureSize
1235
- );
1236
- gl.uniform2ui(
1237
- initializeBucketReferrerUniforms["u_bucketNum"],
1238
- bucketNum.x,
1239
- bucketNum.y
1240
- );
1241
- gl.bindVertexArray(fillScreenVao);
1242
- gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);
1243
- gl.bindVertexArray(null);
1244
- gl.bindFramebuffer(gl.FRAMEBUFFER, null);
1245
- };
1246
-
1247
- const constructBuckets = function() {
1248
- initializeBucket();
1249
- // sort by bitonic sort
1250
- for (let i = 0; i < boidNumN; i++) {
1251
- for (let j = 0; j <= i; j++) {
1252
- swapBucketIndex(i, j);
1253
- }
1254
- }
1255
- initializeBucketRefrrer();
1256
- };
1257
-
1258
- const computeForces = function() {
1259
- gl.bindFramebuffer(gl.FRAMEBUFFER, forceFbObj.framebuffer);
1260
- gl.viewport(0.0, 0.0, boidTextureSize, boidTextureSize);
1261
- gl.useProgram(computeForceProgram);
1262
- setTextureAsUniform(
1263
- gl,
1264
- 0,
1265
- boidFbObjR.positionTexture,
1266
- computeForceUniforms["u_positionTexture"]
1267
- );
1268
- setTextureAsUniform(
1269
- gl,
1270
- 1,
1271
- boidFbObjR.velocityTexture,
1272
- computeForceUniforms["u_velocityTexture"]
1273
- );
1274
- setTextureAsUniform(
1275
- gl,
1276
- 2,
1277
- bucketFbObjR.bucketTexture,
1278
- computeForceUniforms["u_bucketTexture"]
1279
- );
1280
- setTextureAsUniform(
1281
- gl,
1282
- 3,
1283
- bucketReferrerFbObj.bucketReferrerTexture,
1284
- computeForceUniforms["u_bucketReferrerTexture"]
1285
- );
1286
- gl.uniform1ui(computeForceUniforms["u_boidNum"], boidNum);
1287
- gl.uniform1f(
1288
- computeForceUniforms["u_maxSpeed"],
1289
- parameters.dynamic["max speed"]
1290
- );
1291
- gl.uniform1f(
1292
- computeForceUniforms["u_maxForce"],
1293
- parameters.dynamic["max force"]
1294
- );
1295
- gl.uniform1f(
1296
- computeForceUniforms["u_boundaryIntensity"],
1297
- parameters.dynamic["boundary intensity"]
1298
- );
1299
- gl.uniform1f(computeForceUniforms["u_bucketSize"], bucketSize);
1300
- gl.uniform2i(
1301
- computeForceUniforms["u_bucketNum"],
1302
- bucketNum.x,
1303
- bucketNum.y
1304
- );
1305
- gl.uniform2f(
1306
- computeForceUniforms["u_simulationSpace"],
1307
- simulationSpace.x,
1308
- simulationSpace.y
1309
- );
1310
- gl.uniform3f(
1311
- computeForceUniforms["u_radius"],
1312
- separationRadius,
1313
- alignmentRadius,
1314
- cohesionRadius
1315
- );
1316
- gl.uniform3f(
1317
- computeForceUniforms["u_weight"],
1318
- parameters.dynamic["separation weight"],
1319
- parameters.dynamic["alignment weight"],
1320
- parameters.dynamic["cohesion weight"]
1321
- );
1322
- gl.bindVertexArray(fillScreenVao);
1323
- gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);
1324
- gl.bindVertexArray(null);
1325
- gl.bindFramebuffer(gl.FRAMEBUFFER, null);
1326
- };
1327
-
1328
- const updateBoids = function(deltaTime) {
1329
- gl.bindFramebuffer(gl.FRAMEBUFFER, boidFbObjW.framebuffer);
1330
- gl.viewport(0.0, 0.0, boidTextureSize, boidTextureSize);
1331
- gl.useProgram(updateBoidProgram);
1332
- setTextureAsUniform(
1333
- gl,
1334
- 0,
1335
- boidFbObjR.positionTexture,
1336
- updateBoidUniforms["u_positionTexture"]
1337
- );
1338
- setTextureAsUniform(
1339
- gl,
1340
- 1,
1341
- boidFbObjR.velocityTexture,
1342
- updateBoidUniforms["u_velocityTexture"]
1343
- );
1344
- setTextureAsUniform(
1345
- gl,
1346
- 2,
1347
- forceFbObj.forceTexture,
1348
- updateBoidUniforms["u_forceTexture"]
1349
- );
1350
- gl.uniform1f(updateBoidUniforms["u_deltaTime"], deltaTime);
1351
- gl.uniform1ui(updateBoidUniforms["u_boidNum"], boidNum);
1352
- gl.uniform1ui(
1353
- updateBoidUniforms["u_boidTextureSize"],
1354
- boidTextureSize
1355
- );
1356
- gl.uniform1f(
1357
- updateBoidUniforms["u_maxSpeed"],
1358
- parameters.dynamic["max speed"]
1359
- );
1360
- gl.uniform2f(
1361
- updateBoidUniforms["u_simulationSpace"],
1362
- simulationSpace.x,
1363
- simulationSpace.y
1364
- );
1365
- gl.bindVertexArray(fillScreenVao);
1366
- gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);
1367
- gl.bindVertexArray(null);
1368
- gl.bindFramebuffer(gl.FRAMEBUFFER, null);
1369
- swapBoidFbObj();
1370
- };
1371
-
1372
- const stepSimulation = function(deltaTime) {
1373
- constructBuckets();
1374
- computeForces();
1375
- updateBoids(deltaTime);
1376
- };
1377
-
1378
- const renderBoids = function() {
1379
- gl.viewport(0.0, 0.0, canvas.width, canvas.height);
1380
- gl.clear(gl.COLOR_BUFFER_BIT);
1381
-
1382
- gl.useProgram(renderBoidProgram);
1383
- setTextureAsUniform(
1384
- gl,
1385
- 0,
1386
- boidFbObjR.positionTexture,
1387
- renderBoidUniforms["u_positionTexture"]
1388
- );
1389
- setTextureAsUniform(
1390
- gl,
1391
- 1,
1392
- boidFbObjR.velocityTexture,
1393
- renderBoidUniforms["u_velocityTexture"]
1394
- );
1395
- gl.uniform2f(
1396
- renderBoidUniforms["u_canvasSize"],
1397
- canvas.width,
1398
- canvas.height
1399
- );
1400
- gl.uniform2f(
1401
- renderBoidUniforms["u_simulationSpace"],
1402
- simulationSpace.x,
1403
- simulationSpace.y
1404
- );
1405
- gl.uniform1f(
1406
- renderBoidUniforms["u_boidSize"],
1407
- parameters.dynamic["boid size"]
1408
- );
1409
-
1410
- gl.drawArrays(gl.POINTS, 0, boidNum);
1411
- };
1412
-
1413
- initializeBoids();
1414
-
1415
- gl.clearColor(0.2, 0.2, 0.2, 1.0);
1416
- let previousTime = performance.now();
1417
- const render = function() {
1418
- const currentTime = performance.now();
1419
- const deltaTime = Math.min(
1420
- 0.05,
1421
- (currentTime - previousTime) * 0.001
1422
- );
1423
- previousTime = currentTime;
1424
-
1425
- stepSimulation(deltaTime);
1426
- renderBoids();
1427
-
1428
- requestId = requestAnimationFrame(render);
1429
- };
1430
- render();
1431
- }
1432
- reset();
1433
- })();